From da537aae83f1decc3ee58ea1e0648c316624f118 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Tue, 24 May 2022 16:05:22 +0200 Subject: [PATCH] FeedbackState as metadata (#627) * SerdeAny MapFeedbackState * Fix macro syntax * alloc * fix * Metadata calibrate and map feedback * metadata feedback states * compile * fmt * Register common generic types * tests * sugar * no_std * fix book * alloc * fix fuzzers * fix * fmt * disable python bindings for libafl * clippy * fmt * fixes * fmt * fix * fix * fix * fix * fix * release autofix * fix * fix * fix * fmt * fix * fix * name * fix Co-authored-by: Dominik Maier --- bindings/pylibafl/Cargo.toml | 4 +- bindings/pylibafl/src/lib.rs | 8 +- docs/src/baby_fuzzer/baby_fuzzer.md | 23 +- fuzzers/baby_fuzzer/src/main.rs | 23 +- fuzzers/baby_fuzzer_gramatron/src/main.rs | 18 +- fuzzers/baby_fuzzer_grimoire/src/main.rs | 18 +- fuzzers/baby_fuzzer_nautilus/src/main.rs | 22 +- fuzzers/baby_fuzzer_tokens/src/main.rs | 18 +- .../baby_fuzzer_with_forkexecutor/src/main.rs | 18 +- fuzzers/baby_no_std/src/main.rs | 18 +- .../c_code_with_fork_executor/src/main.rs | 23 +- .../src/main.rs | 23 +- .../command_executor/src/main.rs | 28 +- .../forkserver_executor/src/main.rs | 24 +- .../rust_code_with_fork_executor/src/main.rs | 23 +- .../src/main.rs | 23 +- fuzzers/forkserver_simple/src/main.rs | 33 +- fuzzers/frida_libpng/src/fuzzer.rs | 85 +-- fuzzers/fuzzbench/src/lib.rs | 28 +- fuzzers/fuzzbench_fork_qemu/Cargo.toml | 2 +- fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs | 28 +- fuzzers/fuzzbench_qemu/src/fuzzer.rs | 28 +- fuzzers/fuzzbench_text/src/lib.rs | 51 +- fuzzers/fuzzbench_weighted/src/lib.rs | 28 +- fuzzers/libafl_atheris/src/lib.rs | 24 +- fuzzers/libfuzzer_libmozjpeg/src/lib.rs | 32 +- fuzzers/libfuzzer_libpng/src/lib.rs | 21 +- .../libfuzzer_libpng_accounting/src/lib.rs | 20 +- fuzzers/libfuzzer_libpng_ctx/src/lib.rs | 20 +- fuzzers/libfuzzer_libpng_launcher/src/lib.rs | 20 +- fuzzers/libfuzzer_reachability/src/lib.rs | 16 +- fuzzers/libfuzzer_stb_image/src/main.rs | 18 +- .../fuzzer/src/main.rs | 22 +- fuzzers/push_harness/src/main.rs | 18 +- fuzzers/push_stage_harness/src/main.rs | 18 +- fuzzers/qemu_launcher/src/fuzzer.rs | 20 +- fuzzers/tutorial/src/lib.rs | 25 +- fuzzers/tutorial/src/metadata.rs | 6 +- libafl/Cargo.toml | 6 +- libafl/src/bolts/serdeany.rs | 98 ++-- libafl/src/corpus/mod.rs | 2 +- libafl/src/events/llmp.rs | 2 +- libafl/src/executors/inprocess.rs | 14 +- libafl/src/executors/mod.rs | 149 +----- libafl/src/feedbacks/map.rs | 492 ++++++++++++++---- libafl/src/feedbacks/mod.rs | 228 ++++++-- libafl/src/feedbacks/new_hash_feedback.rs | 126 ++--- libafl/src/feedbacks/owned.rs | 188 +++++++ libafl/src/lib.rs | 11 +- libafl/src/mutators/mutations.rs | 3 +- libafl/src/mutators/scheduled.rs | 6 +- libafl/src/observers/map.rs | 124 +++-- libafl/src/observers/mod.rs | 119 +++++ .../src/schedulers/probabilistic_sampling.rs | 3 +- libafl/src/schedulers/queue.rs | 2 +- libafl/src/stages/calibrate.rs | 34 +- libafl/src/state/mod.rs | 252 +++------ libafl_concolic/symcc_runtime/symcc | 2 +- libafl_sugar/src/forkserver.rs | 19 +- libafl_sugar/src/inmemory.rs | 19 +- libafl_sugar/src/qemu.rs | 19 +- 61 files changed, 1684 insertions(+), 1111 deletions(-) create mode 100644 libafl/src/feedbacks/owned.rs diff --git a/bindings/pylibafl/Cargo.toml b/bindings/pylibafl/Cargo.toml index fe497f1d64..394ecd473b 100644 --- a/bindings/pylibafl/Cargo.toml +++ b/bindings/pylibafl/Cargo.toml @@ -7,8 +7,8 @@ edition = "2021" pyo3 = { version = "0.15", features = ["extension-module"] } libafl_qemu = { path = "../../libafl_qemu", version = "0.7", features = ["python"] } libafl_sugar = { path = "../../libafl_sugar", version = "0.7", features = ["python"] } -libafl = { path = "../../libafl", version = "0.7", features = ["python"] } - +#libafl = { path = "../../libafl", version = "0.7", features = ["python"] } +libafl = { path = "../../libafl", version = "0.7" } [build-dependencies] pyo3-build-config = { version = "0.15" } diff --git a/bindings/pylibafl/src/lib.rs b/bindings/pylibafl/src/lib.rs index 7bc8d36a00..af5b387294 100644 --- a/bindings/pylibafl/src/lib.rs +++ b/bindings/pylibafl/src/lib.rs @@ -1,4 +1,4 @@ -use libafl; +//use libafl; use libafl_qemu; use libafl_sugar; use pyo3::prelude::*; @@ -14,9 +14,9 @@ pub fn python_module(py: Python, m: &PyModule) -> PyResult<()> { libafl_qemu::python_module(py, qemu_module)?; m.add_submodule(qemu_module)?; - let libafl_module = PyModule::new(py, "libafl")?; - libafl::python_module(py, libafl_module)?; - m.add_submodule(libafl_module)?; + //let libafl_module = PyModule::new(py, "libafl")?; + //libafl::python_module(py, libafl_module)?; + //m.add_submodule(libafl_module)?; Ok(()) } diff --git a/docs/src/baby_fuzzer/baby_fuzzer.md b/docs/src/baby_fuzzer/baby_fuzzer.md index dbd9a92596..39e015c33e 100644 --- a/docs/src/baby_fuzzer/baby_fuzzer.md +++ b/docs/src/baby_fuzzer/baby_fuzzer.md @@ -114,8 +114,9 @@ let mut state = StdState::new( // Corpus in which we store solutions (crashes in this example), // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), - (), -); + &mut (), + &mut () +).unwrap(); ``` It takes a random number generator, that is part of the fuzzer state, in this case, we use the default one `StdRand` but you can choose a different one. We seed it with the current nanoseconds. @@ -273,7 +274,7 @@ let mut executor = InProcessExecutor::new( .expect("Failed to create the Executor".into()); ``` -Now that the fuzzer can observe which condition is satisfied, we need a way to rate an input as interesting (i.e. worth of addition to the corpus) based on this observation. Here comes the notion of Feedback. The Feedback is part of the State and provides a way to rate input and its corresponding execution as interesting looking for the information in the observers. Feedbacks can maintain a cumulative state of the information seen so far in a so-called FeedbackState instance, in our case it maintains the set of conditions satisfied in the previous runs. +Now that the fuzzer can observe which condition is satisfied, we need a way to rate an input as interesting (i.e. worth of addition to the corpus) based on this observation. Here comes the notion of Feedback. The Feedback is part of the State and provides a way to rate input and its corresponding execution as interesting looking for the information in the observers. Feedbacks can maintain a cumulative state of the information seen so far in a metadata in the State, in our case it maintains the set of conditions satisfied in the previous runs. We use MaxMapFeedback, a feedback that implements a novelty search over the map of the MapObserver. Basically, if there is a value in the observer's map that is greater than the maximum value registered so far for the same entry, it rates the input as interesting and updates its state. @@ -286,20 +287,17 @@ extern crate libafl; use libafl::{ bolts::{current_nanos, rands::StdRand, tuples::tuple_list}, corpus::{InMemoryCorpus, OnDiskCorpus}, - feedbacks::{MapFeedbackState, MaxMapFeedback, CrashFeedback}, + feedbacks::{MaxMapFeedback, CrashFeedback}, fuzzer::StdFuzzer, state::StdState, observers::StdMapObserver, }; -// The state of the edges feedback. -let feedback_state = MapFeedbackState::with_observer(&observer); - // Feedback to rate the interestingness of an input -let feedback = MaxMapFeedback::new(&feedback_state, &observer); +let mut feedback = MaxMapFeedback::new(&feedback_state, &observer); // A feedback to choose if an input is a solution or not -let objective = CrashFeedback::new(); +let mut objective = CrashFeedback::new(); // create a State from scratch let mut state = StdState::new( @@ -310,10 +308,9 @@ let mut state = StdState::new( // Corpus in which we store solutions (crashes in this example), // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), - // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), -); + &mut feedback, + &mut objective +).unwrap(); // ... diff --git a/fuzzers/baby_fuzzer/src/main.rs b/fuzzers/baby_fuzzer/src/main.rs index 5b2dda45da..f3824f3912 100644 --- a/fuzzers/baby_fuzzer/src/main.rs +++ b/fuzzers/baby_fuzzer/src/main.rs @@ -8,7 +8,7 @@ use libafl::{ corpus::{InMemoryCorpus, OnDiskCorpus}, events::SimpleEventManager, executors::{inprocess::InProcessExecutor, ExitKind}, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback}, fuzzer::{Fuzzer, StdFuzzer}, generators::RandPrintablesGenerator, inputs::{BytesInput, HasTargetBytes}, @@ -41,7 +41,7 @@ pub fn main() { signals_set(2); if buf.len() > 2 && buf[2] == b'c' { #[cfg(unix)] - panic!("=("); + panic!("Artificial bug triggered =)"); // panic!() raises a STATUS_STACK_BUFFER_OVERRUN exception which cannot be caught by the exception handler. // Here we make it raise STATUS_ACCESS_VIOLATION instead. @@ -58,16 +58,14 @@ pub fn main() { }; // Create an observation channel using the signals map - let observer = StdMapObserver::new("signals", unsafe { &mut SIGNALS }); - - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&observer); + let observer = + unsafe { StdMapObserver::new_from_ptr("signals", SIGNALS.as_mut_ptr(), SIGNALS.len()) }; // Feedback to rate the interestingness of an input - let feedback = MaxMapFeedback::new(&feedback_state, &observer); + let mut feedback = MaxMapFeedback::new(&observer); // A feedback to choose if an input is a solution or not - let objective = CrashFeedback::new(); + let mut objective = CrashFeedback::new(); // create a State from scratch let mut state = StdState::new( @@ -79,9 +77,12 @@ pub fn main() { // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), - ); + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, + ) + .unwrap(); // The Monitor trait define how the fuzzer stats are displayed to the user let mon = SimpleMonitor::new(|s| println!("{}", s)); diff --git a/fuzzers/baby_fuzzer_gramatron/src/main.rs b/fuzzers/baby_fuzzer_gramatron/src/main.rs index 6008bcf3f1..4361bbc000 100644 --- a/fuzzers/baby_fuzzer_gramatron/src/main.rs +++ b/fuzzers/baby_fuzzer_gramatron/src/main.rs @@ -13,7 +13,7 @@ use libafl::{ corpus::{InMemoryCorpus, OnDiskCorpus}, events::SimpleEventManager, executors::{inprocess::InProcessExecutor, ExitKind}, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback}, fuzzer::{Fuzzer, StdFuzzer}, generators::{Automaton, GramatronGenerator}, inputs::GramatronInput, @@ -61,14 +61,11 @@ pub fn main() { // Create an observation channel using the signals map let observer = StdMapObserver::new("signals", unsafe { &mut SIGNALS }); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&observer); - // Feedback to rate the interestingness of an input - let feedback = MaxMapFeedback::new(&feedback_state, &observer); + let mut feedback = MaxMapFeedback::new(&observer); // A feedback to choose if an input is a solution or not - let objective = CrashFeedback::new(); + let mut objective = CrashFeedback::new(); // create a State from scratch let mut state = StdState::new( @@ -80,9 +77,12 @@ pub fn main() { // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), - ); + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, + ) + .unwrap(); // The Monitor trait define how the fuzzer stats are reported to the user let monitor = SimpleMonitor::new(|s| println!("{}", s)); diff --git a/fuzzers/baby_fuzzer_grimoire/src/main.rs b/fuzzers/baby_fuzzer_grimoire/src/main.rs index b01165fcfb..b96c812735 100644 --- a/fuzzers/baby_fuzzer_grimoire/src/main.rs +++ b/fuzzers/baby_fuzzer_grimoire/src/main.rs @@ -9,7 +9,7 @@ use libafl::{ corpus::{InMemoryCorpus, OnDiskCorpus}, events::SimpleEventManager, executors::{inprocess::InProcessExecutor, ExitKind}, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback}, fuzzer::{Evaluator, Fuzzer, StdFuzzer}, inputs::{GeneralizedInput, HasTargetBytes}, monitors::SimpleMonitor, @@ -92,14 +92,11 @@ pub fn main() { // Create an observation channel using the signals map let observer = StdMapObserver::new("signals", unsafe { &mut SIGNALS }); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&observer); - // Feedback to rate the interestingness of an input - let feedback = MaxMapFeedback::new_tracking(&feedback_state, &observer, false, true); + let mut feedback = MaxMapFeedback::new_tracking(&observer, false, true); // A feedback to choose if an input is a solution or not - let objective = CrashFeedback::new(); + let mut objective = CrashFeedback::new(); // create a State from scratch let mut state = StdState::new( @@ -111,9 +108,12 @@ pub fn main() { // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), - ); + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, + ) + .unwrap(); if state.metadata().get::().is_none() { state.add_metadata(Tokens::from([b"FOO".to_vec(), b"BAR".to_vec()])); diff --git a/fuzzers/baby_fuzzer_nautilus/src/main.rs b/fuzzers/baby_fuzzer_nautilus/src/main.rs index baf0699cd9..f16a944dca 100644 --- a/fuzzers/baby_fuzzer_nautilus/src/main.rs +++ b/fuzzers/baby_fuzzer_nautilus/src/main.rs @@ -9,9 +9,7 @@ use libafl::{ events::SimpleEventManager, executors::{inprocess::InProcessExecutor, ExitKind}, feedback_or, - feedbacks::{ - CrashFeedback, MapFeedbackState, MaxMapFeedback, NautilusChunksMetadata, NautilusFeedback, - }, + feedbacks::{CrashFeedback, MaxMapFeedback, NautilusChunksMetadata, NautilusFeedback}, fuzzer::{Fuzzer, StdFuzzer}, generators::{NautilusContext, NautilusGenerator}, inputs::NautilusInput, @@ -51,17 +49,14 @@ pub fn main() { // Create an observation channel using the signals map let observer = StdMapObserver::new("signals", unsafe { &mut SIGNALS }); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&observer); - // Feedback to rate the interestingness of an input - let feedback = feedback_or!( - MaxMapFeedback::new(&feedback_state, &observer), + let mut feedback = feedback_or!( + MaxMapFeedback::new(&observer), NautilusFeedback::new(&context) ); // A feedback to choose if an input is a solution or not - let objective = CrashFeedback::new(); + let mut objective = CrashFeedback::new(); // create a State from scratch let mut state = StdState::new( @@ -73,9 +68,12 @@ pub fn main() { // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), - ); + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, + ) + .unwrap(); if state.metadata().get::().is_none() { state.add_metadata(NautilusChunksMetadata::new("/tmp/".into())); diff --git a/fuzzers/baby_fuzzer_tokens/src/main.rs b/fuzzers/baby_fuzzer_tokens/src/main.rs index 8429db3f67..0cb1c0e040 100644 --- a/fuzzers/baby_fuzzer_tokens/src/main.rs +++ b/fuzzers/baby_fuzzer_tokens/src/main.rs @@ -9,7 +9,7 @@ use libafl::{ corpus::{InMemoryCorpus, OnDiskCorpus}, events::SimpleEventManager, executors::{inprocess::InProcessExecutor, ExitKind}, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback}, fuzzer::{Evaluator, Fuzzer, StdFuzzer}, inputs::{EncodedInput, InputDecoder, InputEncoder, NaiveTokenizer, TokenInputEncoderDecoder}, monitors::SimpleMonitor, @@ -69,14 +69,11 @@ pub fn main() { // Create an observation channel using the signals map let observer = StdMapObserver::new("signals", unsafe { &mut SIGNALS }); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&observer); - // Feedback to rate the interestingness of an input - let feedback = MaxMapFeedback::new(&feedback_state, &observer); + let mut feedback = MaxMapFeedback::new(&observer); // A feedback to choose if an input is a solution or not - let objective = CrashFeedback::new(); + let mut objective = CrashFeedback::new(); // create a State from scratch let mut state = StdState::new( @@ -88,9 +85,12 @@ pub fn main() { // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), - ); + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, + ) + .unwrap(); // The Monitor trait define how the fuzzer stats are reported to the user let monitor = SimpleMonitor::new(|s| println!("{}", s)); diff --git a/fuzzers/baby_fuzzer_with_forkexecutor/src/main.rs b/fuzzers/baby_fuzzer_with_forkexecutor/src/main.rs index dc6aa75aee..d11b63f869 100644 --- a/fuzzers/baby_fuzzer_with_forkexecutor/src/main.rs +++ b/fuzzers/baby_fuzzer_with_forkexecutor/src/main.rs @@ -14,7 +14,7 @@ use libafl::{ corpus::{InMemoryCorpus, OnDiskCorpus}, events::SimpleEventManager, executors::{ExitKind, InProcessForkExecutor}, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback}, fuzzer::{Fuzzer, StdFuzzer}, generators::RandPrintablesGenerator, inputs::{BytesInput, HasTargetBytes}, @@ -68,14 +68,11 @@ pub fn main() { let observer = StdMapObserver::new("signals", signals_clone.as_mut_slice()); // Create a stacktrace observer to add the observers tuple - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&observer); - // Feedback to rate the interestingness of an input, obtained by ANDing the interestingness of both feedbacks - let feedback = MaxMapFeedback::new(&feedback_state, &observer); + let mut feedback = MaxMapFeedback::new(&observer); // A feedback to choose if an input is a solution or not - let objective = CrashFeedback::new(); + let mut objective = CrashFeedback::new(); // create a State from scratch let mut state = StdState::new( @@ -87,9 +84,12 @@ pub fn main() { // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), - ); + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, + ) + .unwrap(); // The Monitor trait define how the fuzzer stats are displayed to the user let mon = SimpleMonitor::new(|s| println!("{}", s)); diff --git a/fuzzers/baby_no_std/src/main.rs b/fuzzers/baby_no_std/src/main.rs index 9bdefe8b16..d6422de7b0 100644 --- a/fuzzers/baby_no_std/src/main.rs +++ b/fuzzers/baby_no_std/src/main.rs @@ -9,7 +9,7 @@ use libafl::{ corpus::InMemoryCorpus, events::SimpleEventManager, executors::{inprocess::InProcessExecutor, ExitKind}, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback}, fuzzer::{Fuzzer, StdFuzzer}, generators::RandPrintablesGenerator, inputs::{BytesInput, HasTargetBytes}, @@ -77,14 +77,11 @@ pub fn main() { // Create an observation channel using the signals map let observer = StdMapObserver::new("signals", unsafe { &mut SIGNALS }); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&observer); - // Feedback to rate the interestingness of an input - let feedback = MaxMapFeedback::new(&feedback_state, &observer); + let mut feedback = MaxMapFeedback::new(&observer); // A feedback to choose if an input is a solution or not - let objective = CrashFeedback::new(); + let mut objective = CrashFeedback::new(); // create a State from scratch let mut state = StdState::new( @@ -96,9 +93,12 @@ pub fn main() { // on disk so the user can get them after stopping the fuzzer InMemoryCorpus::new(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), - ); + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, + ) + .unwrap(); // The Monitor trait define how the fuzzer stats are reported to the user let monitor = SimpleMonitor::new(|s| { diff --git a/fuzzers/backtrace_baby_fuzzers/c_code_with_fork_executor/src/main.rs b/fuzzers/backtrace_baby_fuzzers/c_code_with_fork_executor/src/main.rs index 7b29ada057..3bd2b70379 100644 --- a/fuzzers/backtrace_baby_fuzzers/c_code_with_fork_executor/src/main.rs +++ b/fuzzers/backtrace_baby_fuzzers/c_code_with_fork_executor/src/main.rs @@ -14,9 +14,7 @@ use libafl::{ events::SimpleEventManager, executors::InProcessForkExecutor, feedback_and, - feedbacks::{ - CrashFeedback, MapFeedbackState, MaxMapFeedback, NewHashFeedback, NewHashFeedbackState, - }, + feedbacks::{CrashFeedback, MaxMapFeedback, NewHashFeedback}, fuzzer::{Fuzzer, StdFuzzer}, generators::RandPrintablesGenerator, inputs::{BytesInput, HasTargetBytes}, @@ -59,17 +57,13 @@ pub fn main() { libafl::observers::HarnessType::Child, ); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&observer); - let st_feedback_state = NewHashFeedbackState::::with_observer(&bt_observer); - // Feedback to rate the interestingness of an input, obtained by ANDing the interestingness of both feedbacks - let feedback = MaxMapFeedback::new(&feedback_state, &observer); + let mut feedback = MaxMapFeedback::new(&observer); // A feedback to choose if an input is a solution or not - let objective = feedback_and!( + let mut objective = feedback_and!( CrashFeedback::new(), - NewHashFeedback::::new_with_observer("BacktraceObserver", &bt_observer) + NewHashFeedback::::new(&bt_observer) ); // create a State from scratch @@ -82,9 +76,12 @@ pub fn main() { // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state, st_feedback_state), - ); + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, + ) + .unwrap(); // The Monitor trait define how the fuzzer stats are displayed to the user let mon = SimpleMonitor::new(|s| println!("{}", s)); diff --git a/fuzzers/backtrace_baby_fuzzers/c_code_with_inprocess_executor/src/main.rs b/fuzzers/backtrace_baby_fuzzers/c_code_with_inprocess_executor/src/main.rs index 5bac4277d2..21048f1c45 100644 --- a/fuzzers/backtrace_baby_fuzzers/c_code_with_inprocess_executor/src/main.rs +++ b/fuzzers/backtrace_baby_fuzzers/c_code_with_inprocess_executor/src/main.rs @@ -8,9 +8,7 @@ use libafl::{ corpus::{InMemoryCorpus, OnDiskCorpus}, events::SimpleEventManager, feedback_and, - feedbacks::{ - CrashFeedback, MapFeedbackState, MaxMapFeedback, NewHashFeedback, NewHashFeedbackState, - }, + feedbacks::{CrashFeedback, MaxMapFeedback, NewHashFeedback}, fuzzer::{Fuzzer, StdFuzzer}, generators::RandPrintablesGenerator, inputs::{BytesInput, HasTargetBytes}, @@ -48,17 +46,13 @@ pub fn main() { libafl::observers::HarnessType::InProcess, ); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&observer); - let st_feedback_state = NewHashFeedbackState::::with_observer(&bt_observer); - // Feedback to rate the interestingness of an input, obtained by ANDing the interestingness of both feedbacks - let feedback = MaxMapFeedback::new(&feedback_state, &observer); + let mut feedback = MaxMapFeedback::new(&observer); // A feedback to choose if an input is a solution or not - let objective = feedback_and!( + let mut objective = feedback_and!( CrashFeedback::new(), - NewHashFeedback::::new_with_observer("BacktraceObserver", &bt_observer) + NewHashFeedback::::new(&bt_observer) ); // create a State from scratch @@ -71,9 +65,12 @@ pub fn main() { // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state, st_feedback_state), - ); + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, + ) + .unwrap(); // The Monitor trait define how the fuzzer stats are displayed to the user let mon = SimpleMonitor::new(|s| println!("{}", s)); diff --git a/fuzzers/backtrace_baby_fuzzers/command_executor/src/main.rs b/fuzzers/backtrace_baby_fuzzers/command_executor/src/main.rs index 2b214fa8d4..bb03d8cfb4 100644 --- a/fuzzers/backtrace_baby_fuzzers/command_executor/src/main.rs +++ b/fuzzers/backtrace_baby_fuzzers/command_executor/src/main.rs @@ -10,9 +10,7 @@ use libafl::{ events::SimpleEventManager, executors::command::CommandConfigurator, feedback_and, - feedbacks::{ - CrashFeedback, MapFeedbackState, MaxMapFeedback, NewHashFeedback, NewHashFeedbackState, - }, + feedbacks::{CrashFeedback, MaxMapFeedback, NewHashFeedback}, fuzzer::{Fuzzer, StdFuzzer}, generators::RandPrintablesGenerator, inputs::{HasTargetBytes, Input}, @@ -43,22 +41,15 @@ pub fn main() { // Create a stacktrace observer let bt_observer = ASANBacktraceObserver::new("ASANBacktraceObserver"); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&observer); - let bt_feedback_state = NewHashFeedbackState::::with_observer(&bt_observer); - // Feedback to rate the interestingness of an input, obtained by ANDing the interestingness of both feedbacks - let feedback = MaxMapFeedback::new(&feedback_state, &observer); + let mut feedback = MaxMapFeedback::new(&observer); // A feedback to choose if an input is a solution or not - let objective = feedback_and!( + let mut objective = feedback_and!( CrashFeedback::new(), - NewHashFeedback::::new_with_observer( - "ASANBacktraceObserver", - &bt_observer - ) + NewHashFeedback::::new(&bt_observer) ); - // let objective = CrashFeedback::new(); + // let mut objective = CrashFeedback::new(); // create a State from scratch let mut state = StdState::new( @@ -70,9 +61,12 @@ pub fn main() { // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state, bt_feedback_state), - ); + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, + ) + .unwrap(); // The Monitor trait define how the fuzzer stats are displayed to the user let mon = SimpleMonitor::new(|s| println!("{}", s)); diff --git a/fuzzers/backtrace_baby_fuzzers/forkserver_executor/src/main.rs b/fuzzers/backtrace_baby_fuzzers/forkserver_executor/src/main.rs index f8b4ad1fab..772b206e1c 100644 --- a/fuzzers/backtrace_baby_fuzzers/forkserver_executor/src/main.rs +++ b/fuzzers/backtrace_baby_fuzzers/forkserver_executor/src/main.rs @@ -10,9 +10,7 @@ use libafl::{ events::SimpleEventManager, executors::forkserver::ForkserverExecutor, feedback_and, - feedbacks::{ - CrashFeedback, MapFeedbackState, MaxMapFeedback, NewHashFeedback, NewHashFeedbackState, - }, + feedbacks::{CrashFeedback, MaxMapFeedback, NewHashFeedback}, fuzzer::{Fuzzer, StdFuzzer}, generators::RandPrintablesGenerator, inputs::BytesInput, @@ -54,20 +52,13 @@ pub fn main() { let bt_observer = ASANBacktraceObserver::new("ASANBacktraceObserver"); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); - let bt_state = NewHashFeedbackState::::with_observer(&bt_observer); - // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false); + let mut feedback = MaxMapFeedback::new_tracking(&edges_observer, true, false); // A feedback to choose if an input is a solution or not // We want to do the same crash deduplication that AFL does - let objective = feedback_and!( - CrashFeedback::new(), - NewHashFeedback::new_with_observer("NewHashFeedback", &bt_observer) - ); + let mut objective = feedback_and!(CrashFeedback::new(), NewHashFeedback::new(&bt_observer)); // create a State from scratch let mut state = StdState::new( @@ -79,9 +70,12 @@ pub fn main() { // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state, bt_state), - ); + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, + ) + .unwrap(); // The Monitor trait define how the fuzzer stats are reported to the user let monitor = SimpleMonitor::new(|s| println!("{}", s)); diff --git a/fuzzers/backtrace_baby_fuzzers/rust_code_with_fork_executor/src/main.rs b/fuzzers/backtrace_baby_fuzzers/rust_code_with_fork_executor/src/main.rs index 1887a896c2..5534e21453 100644 --- a/fuzzers/backtrace_baby_fuzzers/rust_code_with_fork_executor/src/main.rs +++ b/fuzzers/backtrace_baby_fuzzers/rust_code_with_fork_executor/src/main.rs @@ -15,9 +15,7 @@ use libafl::{ events::SimpleEventManager, executors::{ExitKind, InProcessForkExecutor}, feedback_and, - feedbacks::{ - CrashFeedback, MapFeedbackState, MaxMapFeedback, NewHashFeedback, NewHashFeedbackState, - }, + feedbacks::{CrashFeedback, MaxMapFeedback, NewHashFeedback}, fuzzer::{Fuzzer, StdFuzzer}, generators::RandPrintablesGenerator, inputs::{BytesInput, HasTargetBytes}, @@ -76,17 +74,13 @@ pub fn main() { libafl::observers::HarnessType::Child, ); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&observer); - let bt_feedback_state = NewHashFeedbackState::::with_observer(&bt_observer); - // Feedback to rate the interestingness of an input, obtained by ANDing the interestingness of both feedbacks - let feedback = MaxMapFeedback::new(&feedback_state, &observer); + let mut feedback = MaxMapFeedback::new(&observer); // A feedback to choose if an input is a solution or not - let objective = feedback_and!( + let mut objective = feedback_and!( CrashFeedback::new(), - NewHashFeedback::::new_with_observer("BacktraceObserver", &bt_observer) + NewHashFeedback::::new(&bt_observer) ); // create a State from scratch @@ -99,9 +93,12 @@ pub fn main() { // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state, bt_feedback_state), - ); + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, + ) + .unwrap(); // The Monitor trait define how the fuzzer stats are displayed to the user let mon = SimpleMonitor::new(|s| println!("{}", s)); diff --git a/fuzzers/backtrace_baby_fuzzers/rust_code_with_inprocess_executor/src/main.rs b/fuzzers/backtrace_baby_fuzzers/rust_code_with_inprocess_executor/src/main.rs index ad7c3ea0e6..30f6548387 100644 --- a/fuzzers/backtrace_baby_fuzzers/rust_code_with_inprocess_executor/src/main.rs +++ b/fuzzers/backtrace_baby_fuzzers/rust_code_with_inprocess_executor/src/main.rs @@ -9,9 +9,7 @@ use libafl::{ events::SimpleEventManager, executors::{inprocess::InProcessExecutor, ExitKind}, feedback_and, - feedbacks::{ - CrashFeedback, MapFeedbackState, MaxMapFeedback, NewHashFeedback, NewHashFeedbackState, - }, + feedbacks::{CrashFeedback, MaxMapFeedback, NewHashFeedback}, fuzzer::{Fuzzer, StdFuzzer}, generators::RandPrintablesGenerator, inputs::{BytesInput, HasTargetBytes}, @@ -70,17 +68,13 @@ pub fn main() { libafl::observers::HarnessType::InProcess, ); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&observer); - let hash_state = NewHashFeedbackState::::with_observer(&bt_observer); - // Feedback to rate the interestingness of an input, obtained by ANDing the interestingness of both feedbacks - let feedback = MaxMapFeedback::new(&feedback_state, &observer); + let mut feedback = MaxMapFeedback::new(&observer); // A feedback to choose if an input is a solution or not - let objective = feedback_and!( + let mut objective = feedback_and!( CrashFeedback::new(), - NewHashFeedback::::new_with_observer("NewHashFeedback", &bt_observer) + NewHashFeedback::::new(&bt_observer) ); // create a State from scratch @@ -93,9 +87,12 @@ pub fn main() { // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state, hash_state), - ); + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, + ) + .unwrap(); // The Monitor trait define how the fuzzer stats are displayed to the user let mon = SimpleMonitor::new(|s| println!("{}", s)); diff --git a/fuzzers/forkserver_simple/src/main.rs b/fuzzers/forkserver_simple/src/main.rs index 48e0c4007c..2e1789a2b9 100644 --- a/fuzzers/forkserver_simple/src/main.rs +++ b/fuzzers/forkserver_simple/src/main.rs @@ -1,4 +1,4 @@ -use clap::{App, Arg}; +use clap::{Arg, Command}; use core::time::Duration; use libafl::{ bolts::{ @@ -12,7 +12,7 @@ use libafl::{ events::SimpleEventManager, executors::forkserver::{ForkserverExecutor, TimeoutForkserverExecutor}, feedback_and_fast, feedback_or, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::BytesInput, monitors::SimpleMonitor, @@ -33,7 +33,7 @@ use libafl::bolts::shmem::StdShMemProvider; #[allow(clippy::similar_names)] pub fn main() { - let res = App::new("forkserver_simple") + let res = Command::new("forkserver_simple") .about("Example Forkserver fuzer") .arg( Arg::new("executable") @@ -63,7 +63,7 @@ pub fn main() { .arg( Arg::new("arguments") .help("Arguments passed to the target") - .setting(clap::ArgSettings::MultipleValues) + .multiple_values(true) .takes_value(true), ) .arg( @@ -101,28 +101,22 @@ pub fn main() { // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); - - // The state of the edges feedback for crashes. - let objective_state = MapFeedbackState::new("crash_edges", MAP_SIZE); - // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( + let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + MaxMapFeedback::new_tracking(&edges_observer, true, false), // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); // A feedback to choose if an input is a solution or not // We want to do the same crash deduplication that AFL does - let objective = feedback_and_fast!( + let mut objective = feedback_and_fast!( // Must be a crash CrashFeedback::new(), // Take it onlt if trigger new coverage over crashes - MaxMapFeedback::new(&objective_state, &edges_observer) + MaxMapFeedback::<_, _, _, u8>::new(&edges_observer) ); // create a State from scratch @@ -135,9 +129,12 @@ pub fn main() { // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state, objective_state), - ); + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, + ) + .unwrap(); // The Monitor trait define how the fuzzer stats are reported to the user let monitor = SimpleMonitor::new(|s| println!("{}", s)); @@ -163,7 +160,7 @@ pub fn main() { let mut tokens = Tokens::new(); let forkserver = ForkserverExecutor::builder() - .program(res.value_of("executable").unwrap().to_string()) + .program(res.value_of("executable").unwrap()) .debug_child(debug_child) .shmem_provider(&mut shmem_provider) .autotokens(&mut tokens) diff --git a/fuzzers/frida_libpng/src/fuzzer.rs b/fuzzers/frida_libpng/src/fuzzer.rs index a5bb93a431..e756f70e8e 100644 --- a/fuzzers/frida_libpng/src/fuzzer.rs +++ b/fuzzers/frida_libpng/src/fuzzer.rs @@ -20,8 +20,8 @@ use libafl::{ corpus::{ondisk::OnDiskMetadataFormat, CachedOnDiskCorpus, Corpus, OnDiskCorpus}, events::{llmp::LlmpRestartingEventManager, EventConfig}, executors::{inprocess::InProcessExecutor, ExitKind, ShadowExecutor}, - feedback_or, feedback_or_fast, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, + feedback_and_fast, feedback_or, feedback_or_fast, + feedbacks::{ConstFeedback, CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, @@ -72,9 +72,13 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> { let shmem_provider = StdShMemProvider::new()?; - let mut run_client = |state: Option>, + let mut run_client = |state: Option<_>, mgr: LlmpRestartingEventManager<_, _, _, _>, core_id| { + // The restarting state will spawn the same process again as child, then restarted it each time it crashes. + + // println!("{:?}", mgr.mgr_id()); + let lib = libloading::Library::new(options.clone().harness.unwrap()).unwrap(); let target_func: libloading::Symbol< unsafe extern "C" fn(data: *const u8, size: usize) -> i32, @@ -88,9 +92,7 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> { }; if options.asan && options.asan_cores.contains(core_id) { - (|state: Option>, - mut mgr: LlmpRestartingEventManager<_, _, _, _>, - _core_id| { + (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _, _, _>, _core_id| { let gum = Gum::obtain(); let coverage = CoverageRuntime::new(); @@ -114,26 +116,25 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> { // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); - let feedback_state = MapFeedbackState::with_observer(&edges_observer); - // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( + let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + MaxMapFeedback::new_tracking(&edges_observer, true, false), // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); // Feedbacks to recognize an input as solution #[cfg(unix)] - let objective = feedback_or_fast!( + let mut objective = feedback_or_fast!( CrashFeedback::new(), TimeoutFeedback::new(), - AsanErrorsFeedback::new() + // true enables the AsanErrorFeedback + feedback_and_fast!(ConstFeedback::from(true), AsanErrorsFeedback::new()) ); #[cfg(windows)] - let objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); + let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -149,10 +150,10 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> { Some(OnDiskMetadataFormat::JsonPretty), ) .unwrap(), - // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), + &mut feedback, + &mut objective, ) + .unwrap() }); println!("We're a client, let's fuzz :)"); @@ -216,9 +217,7 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> { Ok(()) })(state, mgr, core_id) } else if options.cmplog && options.cmplog_cores.contains(core_id) { - (|state: Option>, - mut mgr: LlmpRestartingEventManager<_, _, _, _>, - _core_id| { + (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _, _, _>, _core_id| { let gum = Gum::obtain(); let coverage = CoverageRuntime::new(); @@ -237,19 +236,23 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> { // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); - let feedback_state = MapFeedbackState::with_observer(&edges_observer); - // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( + let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + MaxMapFeedback::new_tracking(&edges_observer, true, false), // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); - // Feedbacks to recognize an input as solution - let objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); + #[cfg(unix)] + let mut objective = feedback_or_fast!( + CrashFeedback::new(), + TimeoutFeedback::new(), + feedback_and_fast!(ConstFeedback::from(false), AsanErrorsFeedback::new()) + ); + #[cfg(windows)] + let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -265,10 +268,10 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> { Some(OnDiskMetadataFormat::JsonPretty), ) .unwrap(), - // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), + &mut feedback, + &mut objective, ) + .unwrap() }); println!("We're a client, let's fuzz :)"); @@ -348,9 +351,7 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> { Ok(()) })(state, mgr, core_id) } else { - (|state: Option>, - mut mgr: LlmpRestartingEventManager<_, _, _, _>, - _core_id| { + (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _, _, _>, _core_id| { let gum = Gum::obtain(); let coverage = CoverageRuntime::new(); @@ -368,19 +369,23 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> { // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); - let feedback_state = MapFeedbackState::with_observer(&edges_observer); - // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( + let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + MaxMapFeedback::new_tracking(&edges_observer, true, false), // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); - // Feedbacks to recognize an input as solution - let objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); + #[cfg(unix)] + let mut objective = feedback_or_fast!( + CrashFeedback::new(), + TimeoutFeedback::new(), + feedback_and_fast!(ConstFeedback::from(false), AsanErrorsFeedback::new()) + ); + #[cfg(windows)] + let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -396,10 +401,10 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> { Some(OnDiskMetadataFormat::JsonPretty), ) .unwrap(), - // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), + &mut feedback, + &mut objective, ) + .unwrap() }); println!("We're a client, let's fuzz :)"); diff --git a/fuzzers/fuzzbench/src/lib.rs b/fuzzers/fuzzbench/src/lib.rs index 4db8b93aca..6d9107e556 100644 --- a/fuzzers/fuzzbench/src/lib.rs +++ b/fuzzers/fuzzbench/src/lib.rs @@ -3,7 +3,7 @@ use mimalloc::MiMalloc; #[global_allocator] static GLOBAL: MiMalloc = MiMalloc; -use clap::{App, Arg}; +use clap::{Arg, Command}; use core::{cell::RefCell, time::Duration}; #[cfg(unix)] use nix::{self, unistd::dup}; @@ -30,7 +30,7 @@ use libafl::{ events::SimpleRestartingEventManager, executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor}, feedback_or, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, @@ -64,7 +64,7 @@ pub fn libafl_main() { // Needed only on no_std //RegistryBuilder::register::(); - let res = match App::new("libafl_fuzzbench") + let res = match Command::new("libafl_fuzzbench") .version("0.7.1") .author("AFLplusplus team") .about("LibAFL-based fuzzer for Fuzzbench") @@ -113,7 +113,7 @@ pub fn libafl_main() { env::current_exe() .unwrap_or_else(|_| "fuzzer".into()) .to_string_lossy(), - err.info, + err, ); return; } @@ -260,20 +260,21 @@ fn fuzz( let cmplog = unsafe { &mut CMPLOG_MAP }; let cmplog_observer = CmpLogObserver::new("cmplog", cmplog, true); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); + let map_feedback = MaxMapFeedback::new_tracking(&edges_observer, true, false); + + let calibration = CalibrationStage::new(&map_feedback); // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( + let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + map_feedback, // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); // A feedback to choose if an input is a solution or not - let objective = CrashFeedback::new(); + let mut objective = CrashFeedback::new(); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -286,9 +287,12 @@ fn fuzz( // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(objective_dir).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, ) + .unwrap() }); println!("Let's fuzz :)"); @@ -300,8 +304,6 @@ fn fuzz( println!("Warning: LLVMFuzzerInitialize failed with -1") } - let calibration = CalibrationStage::new(&edges_observer); - // Setup a randomic Input2State stage let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(I2SRandReplace::new()))); diff --git a/fuzzers/fuzzbench_fork_qemu/Cargo.toml b/fuzzers/fuzzbench_fork_qemu/Cargo.toml index 1bdb2c6cec..47fe3618b3 100644 --- a/fuzzers/fuzzbench_fork_qemu/Cargo.toml +++ b/fuzzers/fuzzbench_fork_qemu/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "fuzzbench_qemu" +name = "fuzzbench_fork_qemu" version = "0.7.1" authors = ["Andrea Fioraldi ", "Dominik Maier "] edition = "2021" diff --git a/fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs b/fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs index 67eef8306f..d6257c4401 100644 --- a/fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs +++ b/fuzzers/fuzzbench_fork_qemu/src/fuzzer.rs @@ -1,6 +1,6 @@ //! A singlethreaded QEMU fuzzer that can auto-restart. -use clap::{App, Arg}; +use clap::{Arg, Command}; use core::cell::RefCell; #[cfg(unix)] use nix::{self, unistd::dup}; @@ -27,7 +27,7 @@ use libafl::{ events::SimpleRestartingEventManager, executors::{ExitKind, ShadowExecutor}, feedback_or, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, @@ -62,7 +62,7 @@ pub fn main() { // Needed only on no_std //RegistryBuilder::register::(); - let res = match App::new("libafl_qemu_fuzzbench") + let res = match Command::new("libafl_qemu_fuzzbench") .version("0.4.0") .author("AFLplusplus team") .about("LibAFL-based fuzzer with QEMU for Fuzzbench") @@ -101,7 +101,7 @@ pub fn main() { env::current_exe() .unwrap_or_else(|_| "fuzzer".into()) .to_string_lossy(), - err.info, + err, ); return; } @@ -240,20 +240,21 @@ fn fuzz( let cmplog_observer = CmpLogObserver::new("cmplog", unsafe { CMPLOG_MAP_PTR.as_mut().unwrap() }, true); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); + let map_feedback = MaxMapFeedback::new_tracking(&edges_observer, true, false); + + let calibration = CalibrationStage::new(&map_feedback); // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( + let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + map_feedback, // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); // A feedback to choose if an input is a solution or not - let objective = CrashFeedback::new(); + let mut objective = CrashFeedback::new(); // create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -266,13 +267,14 @@ fn fuzz( // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(objective_dir).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, ) + .unwrap() }); - let calibration = CalibrationStage::new(&edges_observer); - // Setup a randomic Input2State stage let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(I2SRandReplace::new()))); diff --git a/fuzzers/fuzzbench_qemu/src/fuzzer.rs b/fuzzers/fuzzbench_qemu/src/fuzzer.rs index 617b6f05d0..0766ba2ec1 100644 --- a/fuzzers/fuzzbench_qemu/src/fuzzer.rs +++ b/fuzzers/fuzzbench_qemu/src/fuzzer.rs @@ -1,6 +1,6 @@ //! A singlethreaded QEMU fuzzer that can auto-restart. -use clap::{App, Arg}; +use clap::{Arg, Command}; use core::{cell::RefCell, time::Duration}; #[cfg(unix)] use nix::{self, unistd::dup}; @@ -27,7 +27,7 @@ use libafl::{ events::SimpleRestartingEventManager, executors::{ExitKind, ShadowExecutor, TimeoutExecutor}, feedback_or, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, @@ -68,7 +68,7 @@ pub fn main() { // Needed only on no_std //RegistryBuilder::register::(); - let res = match App::new("libafl_qemu_fuzzbench") + let res = match Command::new("libafl_qemu_fuzzbench") .version("0.4.0") .author("AFLplusplus team") .about("LibAFL-based fuzzer with QEMU for Fuzzbench") @@ -113,7 +113,7 @@ pub fn main() { env::current_exe() .unwrap_or_else(|_| "fuzzer".into()) .to_string_lossy(), - err.info, + err, ); return; } @@ -253,20 +253,21 @@ fn fuzz( // Create an observation channel using cmplog map let cmplog_observer = CmpLogObserver::new("cmplog", unsafe { &mut cmplog::CMPLOG_MAP }, true); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); + let map_feedback = MaxMapFeedback::new_tracking(&edges_observer, true, false); + + let calibration = CalibrationStage::new(&map_feedback); // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( + let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + map_feedback, // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); // A feedback to choose if an input is a solution or not - let objective = CrashFeedback::new(); + let mut objective = CrashFeedback::new(); // create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -279,13 +280,14 @@ fn fuzz( // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(objective_dir).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, ) + .unwrap() }); - let calibration = CalibrationStage::new(&edges_observer); - // Setup a randomic Input2State stage let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(I2SRandReplace::new()))); diff --git a/fuzzers/fuzzbench_text/src/lib.rs b/fuzzers/fuzzbench_text/src/lib.rs index 0ed16796ea..e4e0c06dda 100644 --- a/fuzzers/fuzzbench_text/src/lib.rs +++ b/fuzzers/fuzzbench_text/src/lib.rs @@ -3,7 +3,7 @@ use mimalloc::MiMalloc; #[global_allocator] static GLOBAL: MiMalloc = MiMalloc; -use clap::{App, Arg}; +use clap::{Arg, Command}; use content_inspector::inspect; use core::{cell::RefCell, time::Duration}; #[cfg(unix)] @@ -31,7 +31,7 @@ use libafl::{ events::SimpleRestartingEventManager, executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor}, feedback_or, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, GeneralizedInput, HasTargetBytes}, monitors::SimpleMonitor, @@ -70,7 +70,7 @@ pub fn libafl_main() { // Needed only on no_std //RegistryBuilder::register::(); - let res = match App::new("libafl_fuzzbench") + let res = match Command::new("libafl_fuzzbench") .version("0.7.1") .author("AFLplusplus team") .about("LibAFL-based fuzzer for Fuzzbench") @@ -119,7 +119,7 @@ pub fn libafl_main() { env::current_exe() .unwrap_or_else(|_| "fuzzer".into()) .to_string_lossy(), - err.info, + err, ); return; } @@ -321,20 +321,20 @@ fn fuzz_binary( let cmplog = unsafe { &mut CMPLOG_MAP }; let cmplog_observer = CmpLogObserver::new("cmplog", cmplog, true); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); + let map_feedback = MaxMapFeedback::new_tracking(&edges_observer, true, false); + + let calibration = CalibrationStage::new(&map_feedback); // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( + let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, true), + map_feedback, // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); - // A feedback to choose if an input is a solution or not - let objective = CrashFeedback::new(); + let mut objective = CrashFeedback::new(); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -347,9 +347,12 @@ fn fuzz_binary( // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(objective_dir).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, ) + .unwrap() }); println!("Let's fuzz :)"); @@ -361,8 +364,6 @@ fn fuzz_binary( println!("Warning: LLVMFuzzerInitialize failed with -1") } - let calibration = CalibrationStage::new(&edges_observer); - // Setup a randomic Input2State stage let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(I2SRandReplace::new()))); @@ -531,20 +532,21 @@ fn fuzz_text( let cmplog = unsafe { &mut CMPLOG_MAP }; let cmplog_observer = CmpLogObserver::new("cmplog", cmplog, true); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); + // New maximization map feedback linked to the edges observer and the feedback state + let mut map_feedback = MaxMapFeedback::new_tracking(&edges_observer, true, true); + + let calibration = CalibrationStage::new(&map_feedback); // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( - // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, true), + let mut feedback = feedback_or!( + map_feedback, // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); // A feedback to choose if an input is a solution or not - let objective = CrashFeedback::new(); + let mut objective = CrashFeedback::new(); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -557,9 +559,12 @@ fn fuzz_text( // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(objective_dir).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, ) + .unwrap() }); println!("Let's fuzz :)"); @@ -571,8 +576,6 @@ fn fuzz_text( println!("Warning: LLVMFuzzerInitialize failed with -1") } - let calibration = CalibrationStage::new(&edges_observer); - // Setup a randomic Input2State stage let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(I2SRandReplace::new()))); diff --git a/fuzzers/fuzzbench_weighted/src/lib.rs b/fuzzers/fuzzbench_weighted/src/lib.rs index c6ad9d0cb1..deae68abec 100644 --- a/fuzzers/fuzzbench_weighted/src/lib.rs +++ b/fuzzers/fuzzbench_weighted/src/lib.rs @@ -3,7 +3,7 @@ use mimalloc::MiMalloc; #[global_allocator] static GLOBAL: MiMalloc = MiMalloc; -use clap::{App, Arg}; +use clap::{Arg, Command}; use core::{cell::RefCell, time::Duration}; #[cfg(unix)] use nix::{self, unistd::dup}; @@ -30,7 +30,7 @@ use libafl::{ events::SimpleRestartingEventManager, executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor}, feedback_or, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, @@ -64,7 +64,7 @@ pub fn libafl_main() { // Needed only on no_std //RegistryBuilder::register::(); - let res = match App::new("libafl_fuzzbench") + let res = match Command::new("libafl_fuzzbench") .version("0.7.1") .author("AFLplusplus team") .about("LibAFL-based fuzzer for Fuzzbench") @@ -113,7 +113,7 @@ pub fn libafl_main() { env::current_exe() .unwrap_or_else(|_| "fuzzer".into()) .to_string_lossy(), - err.info, + err, ); return; } @@ -260,20 +260,21 @@ fn fuzz( let cmplog = unsafe { &mut CMPLOG_MAP }; let cmplog_observer = CmpLogObserver::new("cmplog", cmplog, true); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); + let map_feedback = MaxMapFeedback::new_tracking(&edges_observer, true, false); + + let calibration = CalibrationStage::new(&map_feedback); // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( + let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + map_feedback, // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); // A feedback to choose if an input is a solution or not - let objective = CrashFeedback::new(); + let mut objective = CrashFeedback::new(); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -286,9 +287,12 @@ fn fuzz( // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(objective_dir).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, ) + .unwrap() }); println!("Let's fuzz :)"); @@ -300,8 +304,6 @@ fn fuzz( println!("Warning: LLVMFuzzerInitialize failed with -1") } - let calibration = CalibrationStage::new(&edges_observer); - // Setup a randomic Input2State stage let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(I2SRandReplace::new()))); diff --git a/fuzzers/libafl_atheris/src/lib.rs b/fuzzers/libafl_atheris/src/lib.rs index 2041ede564..ce27b65629 100644 --- a/fuzzers/libafl_atheris/src/lib.rs +++ b/fuzzers/libafl_atheris/src/lib.rs @@ -3,7 +3,7 @@ //! This is the drop-in replacement for libfuzzer, to be used together with [`Atheris`](https://github.com/google/atheris) //! for python instrumentation and fuzzing. -use clap::{App, AppSettings, Arg}; +use clap::{AppSettings, Arg, Command}; use core::{convert::TryInto, ffi::c_void, slice, time::Duration}; use std::{ env, @@ -25,7 +25,7 @@ use libafl::{ events::EventConfig, executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor}, feedback_or, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, fuzzer::{Fuzzer, StdFuzzer}, generators::RandBytesGenerator, inputs::{BytesInput, HasTargetBytes}, @@ -124,7 +124,7 @@ pub fn LLVMFuzzerRunDriver( println!("Args: {:?}", std::env::args()); - let matches = App::new("libafl_atheris") + let matches = Command::new("libafl_atheris") .version("0.1.0") .setting(AppSettings::AllowExternalSubcommands) .arg(Arg::new("script")) // The python script is the first arg @@ -213,7 +213,7 @@ pub fn LLVMFuzzerRunDriver( // TODO: we need to handle Atheris calls to `exit` on errors somhow. - let mut run_client = |state: Option>, mut mgr, _core_id| { + let mut run_client = |state: Option<_>, mut mgr, _core_id| { // Create an observation channel using the coverage map let edges_observer = unsafe { HitcountsMapObserver::new(StdMapObserver::new_from_ptr( @@ -230,20 +230,17 @@ pub fn LLVMFuzzerRunDriver( let cmplog = unsafe { &mut CMPLOG_MAP }; let cmplog_observer = CmpLogObserver::new("cmplog", cmplog, true); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); - // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( + let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + MaxMapFeedback::new_tracking(&edges_observer, true, false), // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); // A feedback to choose if an input is a solution or not - let objective = feedback_or!(CrashFeedback::new(), TimeoutFeedback::new()); + let mut objective = feedback_or!(CrashFeedback::new(), TimeoutFeedback::new()); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -256,9 +253,12 @@ pub fn LLVMFuzzerRunDriver( // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(output_dir.clone()).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, ) + .unwrap() }); // Create a dictionary if not existing diff --git a/fuzzers/libfuzzer_libmozjpeg/src/lib.rs b/fuzzers/libfuzzer_libmozjpeg/src/lib.rs index 655f7dfdc0..49b90c7749 100644 --- a/fuzzers/libfuzzer_libmozjpeg/src/lib.rs +++ b/fuzzers/libfuzzer_libmozjpeg/src/lib.rs @@ -17,7 +17,7 @@ use libafl::{ events::{setup_restarting_mgr_std, EventConfig}, executors::{inprocess::InProcessExecutor, ExitKind}, feedback_or, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, @@ -86,24 +86,15 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re // Create an observation channel using the allocations map let allocs_observer = StdMapObserver::new("allocs", unsafe { &mut libafl_alloc_map }); - // The state of the edges feedback. - let edges_feedback_state = MapFeedbackState::with_observer(&edges_observer); - - // The state of the cmps feedback. - let cmps_feedback_state = MapFeedbackState::with_observer(&cmps_observer); - - // The state of the allocs feedback. - let allocs_feedback_state = MapFeedbackState::with_observer(&allocs_observer); - // Feedback to rate the interestingness of an input - let feedback = feedback_or!( - MaxMapFeedback::new(&edges_feedback_state, &edges_observer), - MaxMapFeedback::new(&cmps_feedback_state, &cmps_observer), - MaxMapFeedback::new(&allocs_feedback_state, &allocs_observer) + let mut feedback = feedback_or!( + MaxMapFeedback::new(&edges_observer), + MaxMapFeedback::new(&cmps_observer), + MaxMapFeedback::new(&allocs_observer) ); // A feedback to choose if an input is a solution or not - let objective = CrashFeedback::new(); + let mut objective = CrashFeedback::new(); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -116,13 +107,12 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(objective_dir).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!( - edges_feedback_state, - cmps_feedback_state, - allocs_feedback_state - ), + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, ) + .unwrap() }); println!("We're a client, let's fuzz :)"); diff --git a/fuzzers/libfuzzer_libpng/src/lib.rs b/fuzzers/libfuzzer_libpng/src/lib.rs index e2b531de07..4f804a5c8a 100644 --- a/fuzzers/libfuzzer_libpng/src/lib.rs +++ b/fuzzers/libfuzzer_libpng/src/lib.rs @@ -20,7 +20,7 @@ use libafl::{ events::{setup_restarting_mgr_std, EventConfig, EventRestarter}, executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor}, feedback_or, feedback_or_fast, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, @@ -81,20 +81,21 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); + let map_feedback = MaxMapFeedback::new_tracking(&edges_observer, true, false); + + let calibration = CalibrationStage::new(&map_feedback); // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( + let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + map_feedback, // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); // A feedback to choose if an input is a solution or not - let objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); + let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -107,9 +108,12 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(objective_dir).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, ) + .unwrap() }); println!("We're a client, let's fuzz :)"); @@ -129,7 +133,6 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); - let calibration = CalibrationStage::new(&edges_observer); let power = StdPowerMutationalStage::new(mutator, &edges_observer); let mut stages = tuple_list!(calibration, power); diff --git a/fuzzers/libfuzzer_libpng_accounting/src/lib.rs b/fuzzers/libfuzzer_libpng_accounting/src/lib.rs index c8eb0a6704..f610f87452 100644 --- a/fuzzers/libfuzzer_libpng_accounting/src/lib.rs +++ b/fuzzers/libfuzzer_libpng_accounting/src/lib.rs @@ -24,7 +24,7 @@ use libafl::{ events::EventConfig, executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor}, feedback_or, feedback_or_fast, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, @@ -143,7 +143,7 @@ pub fn libafl_main() { let monitor = MultiMonitor::new(|s| println!("{}", s)); - let mut run_client = |state: Option>, mut restarting_mgr, _core_id| { + let mut run_client = |state: Option<_>, mut restarting_mgr, _core_id| { // Create an observation channel using the coverage map let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] }; let edges_observer = HitcountsMapObserver::new(StdMapObserver::new("edges", edges)); @@ -151,20 +151,17 @@ pub fn libafl_main() { // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); - // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( + let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + MaxMapFeedback::new_tracking(&edges_observer, true, false), // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); // A feedback to choose if an input is a solution or not - let objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); + let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -177,9 +174,12 @@ pub fn libafl_main() { // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(&opt.output).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, ) + .unwrap() }); println!("We're a client, let's fuzz :)"); diff --git a/fuzzers/libfuzzer_libpng_ctx/src/lib.rs b/fuzzers/libfuzzer_libpng_ctx/src/lib.rs index 28aa77ad66..5d17dda141 100644 --- a/fuzzers/libfuzzer_libpng_ctx/src/lib.rs +++ b/fuzzers/libfuzzer_libpng_ctx/src/lib.rs @@ -24,7 +24,7 @@ use libafl::{ events::EventConfig, executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor}, feedback_or, feedback_or_fast, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, @@ -141,7 +141,7 @@ pub fn libafl_main() { let monitor = MultiMonitor::new(|s| println!("{}", s)); - let mut run_client = |state: Option>, mut restarting_mgr, _core_id| { + let mut run_client = |state: Option<_>, mut restarting_mgr, _core_id| { // Create an observation channel using the coverage map let edges = unsafe { edges_map_from_ptr() }; let edges_observer = @@ -150,20 +150,17 @@ pub fn libafl_main() { // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); - // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( + let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + MaxMapFeedback::new_tracking(&edges_observer, true, false), // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); // A feedback to choose if an input is a solution or not - let objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); + let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -176,9 +173,12 @@ pub fn libafl_main() { // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(opt.output.clone()).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, ) + .unwrap() }); println!("We're a client, let's fuzz :)"); diff --git a/fuzzers/libfuzzer_libpng_launcher/src/lib.rs b/fuzzers/libfuzzer_libpng_launcher/src/lib.rs index aeae7e00bc..0b62a27c0b 100644 --- a/fuzzers/libfuzzer_libpng_launcher/src/lib.rs +++ b/fuzzers/libfuzzer_libpng_launcher/src/lib.rs @@ -24,7 +24,7 @@ use libafl::{ events::EventConfig, executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor}, feedback_or, feedback_or_fast, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, monitors::tui::TuiMonitor, @@ -141,7 +141,7 @@ pub fn libafl_main() { let monitor = TuiMonitor::new("Test fuzzer on libpng".into(), true); - let mut run_client = |state: Option>, mut restarting_mgr, _core_id| { + let mut run_client = |state: Option<_>, mut restarting_mgr, _core_id| { // Create an observation channel using the coverage map let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] }; let edges_observer = HitcountsMapObserver::new(StdMapObserver::new("edges", edges)); @@ -149,20 +149,17 @@ pub fn libafl_main() { // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); - // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( + let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + MaxMapFeedback::new_tracking(&edges_observer, true, false), // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); // A feedback to choose if an input is a solution or not - let objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); + let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -175,9 +172,12 @@ pub fn libafl_main() { // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(&opt.output).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, ) + .unwrap() }); println!("We're a client, let's fuzz :)"); diff --git a/fuzzers/libfuzzer_reachability/src/lib.rs b/fuzzers/libfuzzer_reachability/src/lib.rs index 84e1f25502..7b83bb1f3d 100644 --- a/fuzzers/libfuzzer_reachability/src/lib.rs +++ b/fuzzers/libfuzzer_reachability/src/lib.rs @@ -11,7 +11,7 @@ use libafl::{ corpus::{Corpus, InMemoryCorpus, OnDiskCorpus}, events::{setup_restarting_mgr_std, EventConfig, EventRestarter}, executors::{inprocess::InProcessExecutor, ExitKind}, - feedbacks::{MapFeedbackState, MaxMapFeedback, ReachabilityFeedback}, + feedbacks::{MaxMapFeedback, ReachabilityFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, @@ -75,14 +75,11 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re let reachability_observer = unsafe { StdMapObserver::new_from_ptr("png.c", __libafl_target_list, TARGET_SIZE) }; - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); - // Feedback to rate the interestingness of an input - let feedback = MaxMapFeedback::new(&feedback_state, &edges_observer); + let mut feedback = MaxMapFeedback::new(&edges_observer); // A feedback to choose if an input is a solution or not - let objective = ReachabilityFeedback::new(&reachability_observer); + let mut objective = ReachabilityFeedback::new(&reachability_observer); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -95,9 +92,12 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(objective_dir).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, ) + .unwrap() }); println!("We're a client, let's fuzz :)"); diff --git a/fuzzers/libfuzzer_stb_image/src/main.rs b/fuzzers/libfuzzer_stb_image/src/main.rs index d978bf7506..35a4a093e7 100644 --- a/fuzzers/libfuzzer_stb_image/src/main.rs +++ b/fuzzers/libfuzzer_stb_image/src/main.rs @@ -12,7 +12,7 @@ use libafl::{ events::{setup_restarting_mgr_std, EventConfig}, executors::{inprocess::InProcessExecutor, ExitKind, ShadowExecutor}, feedback_or, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, @@ -77,20 +77,17 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re let cmplog = unsafe { &mut CMPLOG_MAP }; let cmplog_observer = CmpLogObserver::new("cmplog", cmplog, true); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); - // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( + let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + MaxMapFeedback::new_tracking(&edges_observer, true, false), // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); // A feedback to choose if an input is a solution or not - let objective = CrashFeedback::new(); + let mut objective = CrashFeedback::new(); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -103,9 +100,12 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(objective_dir).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, ) + .unwrap() }); println!("We're a client, let's fuzz :)"); diff --git a/fuzzers/libfuzzer_stb_image_concolic/fuzzer/src/main.rs b/fuzzers/libfuzzer_stb_image_concolic/fuzzer/src/main.rs index b07962154e..72ace93774 100644 --- a/fuzzers/libfuzzer_stb_image_concolic/fuzzer/src/main.rs +++ b/fuzzers/libfuzzer_stb_image_concolic/fuzzer/src/main.rs @@ -25,7 +25,7 @@ use libafl::{ command::CommandConfigurator, inprocess::InProcessExecutor, ExitKind, ShadowExecutor, }, feedback_or, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes, Input}, monitors::MultiMonitor, @@ -116,20 +116,18 @@ fn fuzz( let cmplog = unsafe { &mut CMPLOG_MAP }; let cmplog_observer = CmpLogObserver::new("cmplog", cmplog, true); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); - + // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( + let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + MaxMapFeedback::new_tracking(&edges_observer, true, false), // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); // A feedback to choose if an input is a solution or not - let objective = CrashFeedback::new(); + let mut objective = CrashFeedback::new(); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -141,10 +139,12 @@ fn fuzz( // Corpus in which we store solutions (crashes in this example), // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(objective_dir).unwrap(), - // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), - ) + // States of the feedbacks. + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, + ).unwrap() }); println!("We're a client, let's fuzz :)"); diff --git a/fuzzers/push_harness/src/main.rs b/fuzzers/push_harness/src/main.rs index c6eaadbdc5..137e687815 100644 --- a/fuzzers/push_harness/src/main.rs +++ b/fuzzers/push_harness/src/main.rs @@ -7,7 +7,7 @@ use libafl::{ corpus::{InMemoryCorpus, OnDiskCorpus}, events::SimpleEventManager, executors::{inprocess::InProcessExecutor, ExitKind}, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback}, fuzzer::{Fuzzer, StdFuzzer}, generators::RandPrintablesGenerator, monitors::SimpleMonitor, @@ -41,14 +41,11 @@ fn input_generator() { // Create an observation channel using the signals map let observer = StdMapObserver::new("signals", unsafe { &mut SIGNALS }); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&observer); - // Feedback to rate the interestingness of an input - let feedback = MaxMapFeedback::new(&feedback_state, &observer); + let mut feedback = MaxMapFeedback::new(&observer); // A feedback to choose if an input is a solution or not - let objective = CrashFeedback::new(); + let mut objective = CrashFeedback::new(); // create a State from scratch let mut state = StdState::new( @@ -60,9 +57,12 @@ fn input_generator() { // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), - ); + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, + ) + .unwrap(); // The Monitor trait define how the fuzzer stats are reported to the user let monitor = SimpleMonitor::new(|s| println!("{}", s)); diff --git a/fuzzers/push_stage_harness/src/main.rs b/fuzzers/push_stage_harness/src/main.rs index f89f537942..135be0df59 100644 --- a/fuzzers/push_stage_harness/src/main.rs +++ b/fuzzers/push_stage_harness/src/main.rs @@ -12,7 +12,7 @@ use libafl::{ corpus::{Corpus, InMemoryCorpus, OnDiskCorpus, Testcase}, events::SimpleEventManager, executors::ExitKind, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback}, fuzzer::StdFuzzer, inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, @@ -36,14 +36,11 @@ pub fn main() { // Create an observation channel using the signals map let observer = StdMapObserver::new("signals", unsafe { &mut SIGNALS }); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&observer); - // Feedback to rate the interestingness of an input - let feedback = MaxMapFeedback::::new(&feedback_state, &observer); + let mut feedback = MaxMapFeedback::::new(&observer); // A feedback to choose if an input is a solution or not - let objective = CrashFeedback::new(); + let mut objective = CrashFeedback::new(); // create a State from scratch let mut state = StdState::new( @@ -55,9 +52,12 @@ pub fn main() { // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), - ); + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, + ) + .unwrap(); // The Monitor trait define how the fuzzer stats are reported to the user let monitor = SimpleMonitor::new(|s| println!("{}", s)); diff --git a/fuzzers/qemu_launcher/src/fuzzer.rs b/fuzzers/qemu_launcher/src/fuzzer.rs index c39e42be59..231645f888 100644 --- a/fuzzers/qemu_launcher/src/fuzzer.rs +++ b/fuzzers/qemu_launcher/src/fuzzer.rs @@ -17,7 +17,7 @@ use libafl::{ events::EventConfig, executors::{ExitKind, TimeoutExecutor}, feedback_or, feedback_or_fast, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, monitors::MultiMonitor, @@ -50,7 +50,7 @@ pub fn fuzz() { let broker_port = 1337; let cores = Cores::from_cmdline("0-11").unwrap(); let corpus_dirs = [PathBuf::from("./corpus")]; - let objective_dir = PathBuf::from("./crashes"); + let mut objective_dir = PathBuf::from("./crashes"); // Initialize QEMU env::remove_var("LD_LIBRARY_PATH"); @@ -120,20 +120,17 @@ pub fn fuzz() { // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); - // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( + let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + MaxMapFeedback::new_tracking(&edges_observer, true, false), // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); // A feedback to choose if an input is a solution or not - let objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); + let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -146,9 +143,12 @@ pub fn fuzz() { // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(objective_dir.clone()).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, ) + .unwrap() }); // A minimization+queue policy to get testcasess from the corpus diff --git a/fuzzers/tutorial/src/lib.rs b/fuzzers/tutorial/src/lib.rs index ba9e049aef..dab8a8b8e5 100644 --- a/fuzzers/tutorial/src/lib.rs +++ b/fuzzers/tutorial/src/lib.rs @@ -12,15 +12,15 @@ use libafl::{ events::{setup_restarting_mgr_std, EventConfig, EventRestarter}, executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor}, feedback_or, feedback_or_fast, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, - fuzzer::{Fuzzer, StdFuzzer}, + feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, + fuzzer::StdFuzzer, inputs::HasTargetBytes, monitors::MultiMonitor, observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, schedulers::{powersched::PowerSchedule, PowerQueueScheduler}, stages::{calibrate::CalibrationStage, power::StdPowerMutationalStage}, state::{HasCorpus, StdState}, - Error, + Error, Fuzzer, }; use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM}; @@ -88,21 +88,22 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); + let map_feedback = MaxMapFeedback::new_tracking(&edges_observer, true, false); + + let calibration = CalibrationStage::new(&map_feedback); // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( + let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + map_feedback, // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer), PacketLenFeedback::new() ); // A feedback to choose if an input is a solution or not - let objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); + let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -115,9 +116,12 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(objective_dir).unwrap(), // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, ) + .unwrap() }); println!("We're a client, let's fuzz :)"); @@ -125,7 +129,6 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re // Setup a lain mutator with a mutational stage let mutator = LainMutator::new(); - let calibration = CalibrationStage::new(&edges_observer); let power = StdPowerMutationalStage::new(mutator, &edges_observer); let mut stages = tuple_list!(calibration, power); diff --git a/fuzzers/tutorial/src/metadata.rs b/fuzzers/tutorial/src/metadata.rs index de865833f1..177b4647a0 100644 --- a/fuzzers/tutorial/src/metadata.rs +++ b/fuzzers/tutorial/src/metadata.rs @@ -45,6 +45,7 @@ impl Feedback for PacketLenFeedback where S: HasClientPerfMonitor, { + #[inline] fn is_interesting( &mut self, _state: &mut S, @@ -72,11 +73,6 @@ where .insert(PacketLenMetadata { length: self.len }); Ok(()) } - - #[inline] - fn discard_metadata(&mut self, _state: &mut S, _input: &PacketData) -> Result<(), Error> { - Ok(()) - } } impl Named for PacketLenFeedback { diff --git a/libafl/Cargo.toml b/libafl/Cargo.toml index 20c8b73904..6c5b1e2c23 100644 --- a/libafl/Cargo.toml +++ b/libafl/Cargo.toml @@ -13,13 +13,13 @@ categories = ["development-tools::testing", "emulators", "embedded", "os", "no-s [features] default = ["std", "derive", "llmp_compression", "rand_trait", "fork"] -std = ["serde_json", "serde_json/std", "hostname", "core_affinity", "nix", "serde/std", "bincode", "wait-timeout", "regex", "build_id", "uuid", "tui_monitor", "backtrace"] # print, env, launcher ... support +std = ["serde_json", "serde_json/std", "hostname", "core_affinity", "nix", "serde/std", "bincode", "wait-timeout", "regex", "build_id", "uuid", "tui_monitor", "ctor", "backtrace"] # print, env, launcher ... support derive = ["libafl_derive"] # provide derive(SerdeAny) macro. fork = [] # uses the fork() syscall to spawn children, instead of launching a new command, if supported by the OS (has no effect on Windows, no_std). rand_trait = ["rand_core"] # If set, libafl's rand implementations will implement `rand::Rng` introspection = [] # Include performance statistics of the fuzzing pipeline concolic_mutation = ["z3"] # include a simple concolic mutator based on z3 -python = ["pyo3"] +#python = ["pyo3"] tui_monitor = ["tui", "crossterm"] # enable TuiMonitor with crossterm cli = ["clap"] # expose bolts::cli qemu_cli = ["cli"] @@ -59,13 +59,13 @@ erased-serde = { version = "0.3.12", default-features = false, features = ["allo postcard = { version = "0.7", features = ["alloc"] } # no_std compatible serde serialization fromat bincode = {version = "1.3", optional = true } static_assertions = "1.1.0" -ctor = "0.1.20" num_enum = { version = "0.5.4", default-features = false } typed-builder = "0.9.1" # Implement the builder pattern at compiletime ahash = { version = "0.7", default-features=false, features=["compile-time-rng"] } # The hash function already used in hashbrown intervaltree = { version = "0.2.7", default-features = false, features = ["serde"] } backtrace = {version = "0.3", optional = true} # Used to get the stacktrace in StacktraceObserver +ctor = { optional = true, version = "0.1" } serde_json = { version = "1.0", optional = true, default-features = false, features = ["alloc"] } miniz_oxide = { version = "0.4.4", optional = true} core_affinity = { version = "0.5", git = "https://github.com/s1341/core_affinity_rs", rev = "6648a7a", optional = true } diff --git a/libafl/src/bolts/serdeany.rs b/libafl/src/bolts/serdeany.rs index ca0032d12f..6803949870 100644 --- a/libafl/src/bolts/serdeany.rs +++ b/libafl/src/bolts/serdeany.rs @@ -103,7 +103,7 @@ macro_rules! create_serde_registry_for_trait { *REGISTRY .deserializers .as_ref() - .unwrap() + .expect("Empty types registry") .get(&id) .expect("Cannot deserialize an unregistered type") }; @@ -302,6 +302,15 @@ macro_rules! create_serde_registry_for_trait { map: HashMap>>, } + // Cloning by serializing and deserializing. It ain't fast, but it's honest work. + // We unwrap postcard, it should not have a reason to fail. + impl Clone for NamedSerdeAnyMap { + fn clone(&self) -> Self { + let serialized = postcard::to_allocvec(&self).unwrap(); + postcard::from_bytes(&serialized).unwrap() + } + } + #[allow(unused_qualifications)] impl NamedSerdeAnyMap { /// Get an element by name @@ -496,15 +505,18 @@ macro_rules! create_serde_registry_for_trait { /// Insert an element into this map. #[inline] #[allow(unused_qualifications)] - pub fn insert(&mut self, val: Box, name: &str) { - let id = unpack_type_id((*val).type_id()); + pub fn insert(&mut self, val: T, name: &str) + where + T: $trait_name, + { + let id = unpack_type_id(TypeId::of::()); if !self.map.contains_key(&id) { self.map.insert(id, HashMap::default()); } self.map .get_mut(&id) .unwrap() - .insert(xxhash_rust::xxh3::xxh3_64(name.as_bytes()), val); + .insert(xxhash_rust::xxh3::xxh3_64(name.as_bytes()), Box::new(val)); } /// Returns the `len` of this map. @@ -590,41 +602,36 @@ macro_rules! create_serde_registry_for_trait { create_serde_registry_for_trait!(serdeany_registry, crate::bolts::serdeany::SerdeAny); pub use serdeany_registry::*; -/// Implement a [`SerdeAny`], registering it in the [`RegistryBuilder`] +/// Register a `SerdeAny` type in the [`RegistryBuilder`] #[cfg(feature = "std")] #[macro_export] -macro_rules! impl_serdeany { - ($struct_name:ident) => { - impl $crate::bolts::serdeany::SerdeAny for $struct_name { - fn as_any(&self) -> &dyn ::core::any::Any { - self +macro_rules! register_at_startup { + ($struct_type:ty) => { + const _: () = { + #[$crate::ctor] + fn constructor() { + $crate::bolts::serdeany::RegistryBuilder::register::<$struct_type>(); } - - fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { - self - } - - fn as_any_boxed( - self: ::std::boxed::Box, - ) -> ::std::boxed::Box { - self - } - } - - #[allow(non_snake_case)] - #[$crate::ctor] - fn $struct_name() { - $crate::bolts::serdeany::RegistryBuilder::register::<$struct_name>(); - } + }; }; } -/// Implement [`SerdeAny`] for a type +/// Do nothing for `no_std`, you have to register it manually in `main()` with [`RegistryBuilder::register`] #[cfg(not(feature = "std"))] #[macro_export] +macro_rules! register_at_startup { + ($struct_type:ty) => {}; +} + +/// Implement a [`SerdeAny`], registering it in the [`RegistryBuilder`] when on std +#[macro_export] macro_rules! impl_serdeany { - ($struct_name:ident) => { - impl $crate::bolts::serdeany::SerdeAny for $struct_name { + ($struct_name:ident < $( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+ > $(, < $( $opt:tt ),+ >)*) => + { + impl < $( $lt $( : $clt $(+ $dlt )* )? ),+ > + $crate::bolts::serdeany::SerdeAny + for $struct_name < $( $lt ),+ > + { fn as_any(&self) -> &dyn ::core::any::Any { self } @@ -634,10 +641,37 @@ macro_rules! impl_serdeany { } fn as_any_boxed( - self: ::alloc::boxed::Box, - ) -> ::alloc::boxed::Box { + self: $crate::alloc::boxed::Box<$struct_name < $( $lt ),+ >>, + ) -> $crate::alloc::boxed::Box { self } } + + $( + $crate::register_at_startup!($struct_name < $( $opt ),+ >); + )* + }; + ($struct_name:ident) => + { + impl + $crate::bolts::serdeany::SerdeAny + for $struct_name + { + fn as_any(&self) -> &dyn ::core::any::Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { + self + } + + fn as_any_boxed( + self: $crate::alloc::boxed::Box<$struct_name>, + ) -> $crate::alloc::boxed::Box { + self + } + } + + $crate::register_at_startup!($struct_name); }; } diff --git a/libafl/src/corpus/mod.rs b/libafl/src/corpus/mod.rs index 1c7f94576d..bca5ed8a71 100644 --- a/libafl/src/corpus/mod.rs +++ b/libafl/src/corpus/mod.rs @@ -21,7 +21,7 @@ use core::cell::RefCell; use crate::{inputs::Input, Error}; /// Corpus with all current testcases -pub trait Corpus: serde::Serialize + serde::de::DeserializeOwned +pub trait Corpus: serde::Serialize + for<'de> serde::Deserialize<'de> where I: Input, { diff --git a/libafl/src/events/llmp.rs b/libafl/src/events/llmp.rs index 870218cb50..3f3f98dc8c 100644 --- a/libafl/src/events/llmp.rs +++ b/libafl/src/events/llmp.rs @@ -967,7 +967,7 @@ mod tests { let solutions = InMemoryCorpus::::new(); - let mut state = StdState::new(rand, corpus, solutions, tuple_list!()); + let mut state = StdState::new(rand, corpus, solutions, &mut (), &mut ()).unwrap(); let mut shmem_provider = StdShMemProvider::new().unwrap(); diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index f1f73a0375..3632eb98e4 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -1682,10 +1682,10 @@ pub mod pybind { use pyo3::types::PyBytes; macro_rules! define_python_in_process_executor { - ($struct_name:ident, $py_name:tt, $my_std_state_type_name: ident, $std_state_name: ident, $event_manager_name: ident, $map_observer_name: ident, $std_fuzzer_name: ident) => { + ($struct_name:ident, $py_name:tt, $my_std_state_type_name: ident, $std_state_name: ident, $event_manager_name: ident, $observer_name: ident, $std_fuzzer_name: ident) => { use crate::events::pybind::$event_manager_name; use crate::fuzzer::pybind::$std_fuzzer_name; - use crate::observers::pybind::$map_observer_name; + use crate::observers::map::pybind::$observer_name; use crate::state::pybind::{$my_std_state_type_name, $std_state_name}; #[pyclass(unsendable, name = $py_name)] @@ -1695,7 +1695,7 @@ pub mod pybind { /// Rust wrapped OwnedInProcessExecutor object pub owned_in_process_executor: OwnedInProcessExecutor< BytesInput, - ($map_observer_name, ()), + ($observer_name, ()), $my_std_state_type_name, >, } @@ -1705,7 +1705,7 @@ pub mod pybind { #[new] fn new( harness: PyObject, - py_observer: $map_observer_name, + py_observer: $observer_name, py_fuzzer: &mut $std_fuzzer_name, py_state: &mut $std_state_name, py_event_manager: &mut $event_manager_name, @@ -1734,9 +1734,9 @@ pub mod pybind { } define_python_in_process_executor!( - PythonOwnedInProcessExecutorI8, - "OwnedInProcessExecutorI8", - MyStdStateI8, + PythonOwnedInProcessExecutor, + "OwnedInProcessExecutor", + PythonStdState, PythonStdStateI8, PythonEventManagerI8, PythonMapObserverI8, diff --git a/libafl/src/executors/mod.rs b/libafl/src/executors/mod.rs index 3f7296df63..3ff9d6b9d2 100644 --- a/libafl/src/executors/mod.rs +++ b/libafl/src/executors/mod.rs @@ -195,11 +195,11 @@ pub mod pybind { macro_rules! define_python_executor { ($struct_name_trait:ident, $py_name_trait:tt, $wrapper_name: ident, $my_std_state_type_name: ident, $my_std_fuzzer_type_name: ident, - $event_manager_name: ident, $in_process_executor_name: ident, $map_observer_name: ident) => { + $event_manager_name: ident, $in_process_executor_name: ident, $observer_name: ident) => { use crate::events::pybind::$event_manager_name; use crate::executors::inprocess::pybind::$in_process_executor_name; use crate::fuzzer::pybind::$my_std_fuzzer_type_name; - use crate::observers::map::pybind::$map_observer_name; + use crate::observers::pybind::$observer_name; use crate::state::pybind::$my_std_state_type_name; #[derive(Debug)] @@ -211,44 +211,37 @@ pub mod pybind { #[derive(Debug)] /// Executor + HasObservers Trait binding pub struct $struct_name_trait { - executor: $wrapper_name, + wrapper: $wrapper_name, } impl $struct_name_trait { - fn get_executor( + fn unwrap( &self, ) -> &(impl Executor< $event_manager_name, BytesInput, $my_std_state_type_name, $my_std_fuzzer_type_name, - > + HasObservers) - { + > + HasObservers) { unsafe { - match self.executor { - $wrapper_name::OwnedInProcess(py_owned_inprocess_executor) => { - &(*py_owned_inprocess_executor).owned_in_process_executor - } + match self.wrapper { + $wrapper_name::OwnedInProcess(py_wrapper) => &(*py_wrapper).upcast(), } } } - fn get_mut_executor( + fn unwrap_mut( &mut self, ) -> &mut (impl Executor< $event_manager_name, BytesInput, $my_std_state_type_name, $my_std_fuzzer_type_name, - > + HasObservers< - BytesInput, - ($map_observer_name, ()), - $my_std_state_type_name, - >) { + > + HasObservers) { unsafe { - match self.executor { - $wrapper_name::OwnedInProcess(py_owned_inprocess_executor) => { - &mut (*py_owned_inprocess_executor).owned_in_process_executor + match self.wrapper { + $wrapper_name::OwnedInProcess(py_wrapper) => { + &mut (*py_wrapper).upcast_mut() } } } @@ -262,20 +255,20 @@ pub mod pybind { owned_inprocess_executor: &mut $in_process_executor_name, ) -> Self { Self { - executor: $wrapper_name::OwnedInProcess(owned_inprocess_executor), + wrapper: $wrapper_name::OwnedInProcess(owned_inprocess_executor), } } } - impl HasObservers for $struct_name_trait { + impl HasObservers for $struct_name_trait { // #[inline] - fn observers(&self) -> &($map_observer_name, ()) { - self.get_executor().observers() + fn observers(&self) -> &($observer_name, ()) { + self.unwrap().observers() } #[inline] - fn observers_mut(&mut self) -> &mut ($map_observer_name, ()) { - self.get_mut_executor().observers_mut() + fn observers_mut(&mut self) -> &mut ($observer_name, ()) { + self.unwrap_mut().observers_mut() } } @@ -295,112 +288,26 @@ pub mod pybind { mgr: &mut $event_manager_name, input: &BytesInput, ) -> Result { - self.get_mut_executor() - .run_target(fuzzer, state, mgr, input) + self.unwrap_mut().run_target(fuzzer, state, mgr, input) } } }; } define_python_executor!( - PythonExecutorI8, - "ExecutorI8", - PythonExecutorWrapperI8, - MyStdStateI8, - MyStdFuzzerI8, - PythonEventManagerI8, - PythonOwnedInProcessExecutorI8, - PythonMapObserverI8 - ); - - define_python_executor!( - PythonExecutorI16, - "ExecutorI16", - PythonExecutorWrapperI16, - MyStdStateI16, - MyStdFuzzerI16, - PythonEventManagerI16, - PythonOwnedInProcessExecutorI16, - PythonMapObserverI16 - ); - - define_python_executor!( - PythonExecutorI32, - "ExecutorI32", - PythonExecutorWrapperI32, - MyStdStateI32, - MyStdFuzzerI32, - PythonEventManagerI32, - PythonOwnedInProcessExecutorI32, - PythonMapObserverI32 - ); - - define_python_executor!( - PythonExecutorI64, - "ExecutorI64", - PythonExecutorWrapperI64, - MyStdStateI64, - MyStdFuzzerI64, - PythonEventManagerI64, - PythonOwnedInProcessExecutorI64, - PythonMapObserverI64 - ); - - define_python_executor!( - PythonExecutorU8, - "ExecutorU8", - PythonExecutorWrapperU8, - MyStdStateU8, - MyStdFuzzerU8, - PythonEventManagerU8, - PythonOwnedInProcessExecutorU8, - PythonMapObserverU8 - ); - - define_python_executor!( - PythonExecutorU16, - "ExecutorU16", - PythonExecutorWrapperU16, - MyStdStateU16, - MyStdFuzzerU16, - PythonEventManagerU16, - PythonOwnedInProcessExecutorU16, - PythonMapObserverU16 - ); - - define_python_executor!( - PythonExecutorU32, - "ExecutorU32", - PythonExecutorWrapperU32, - MyStdStateU32, - MyStdFuzzerU32, - PythonEventManagerU32, - PythonOwnedInProcessExecutorU32, - PythonMapObserverU32 - ); - - define_python_executor!( - PythonExecutorU64, - "ExecutorU64", - PythonExecutorWrapperU64, - MyStdStateU64, - MyStdFuzzerU64, - PythonEventManagerU64, - PythonOwnedInProcessExecutorU64, - PythonMapObserverU64 + PythonExecutor, + "Executor", + PythonExecutorWrapper, + PythonStdState, + PythonStdFuzzer, + PythonEventManager, + PythonOwnedInProcessExecutor, + PythonObserver ); /// Register the classes to the python module pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; + m.add_class::()?; Ok(()) } } diff --git a/libafl/src/feedbacks/map.rs b/libafl/src/feedbacks/map.rs index 41fe75abc4..58ef5585f3 100644 --- a/libafl/src/feedbacks/map.rs +++ b/libafl/src/feedbacks/map.rs @@ -7,24 +7,24 @@ use alloc::{ use core::ops::{BitAnd, BitOr}; use core::{fmt::Debug, marker::PhantomData}; use num_traits::PrimInt; -use serde::{Deserialize, Serialize}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; use crate::{ - bolts::{ - tuples::{MatchName, Named}, - AsMutSlice, AsRefIterator, AsSlice, HasRefCnt, - }, + bolts::{tuples::Named, AsMutSlice, AsRefIterator, AsSlice, HasRefCnt}, corpus::Testcase, events::{Event, EventFirer}, executors::ExitKind, - feedbacks::{Feedback, FeedbackState}, + feedbacks::{Feedback, HasObserverName}, inputs::Input, monitors::UserStats, observers::{MapObserver, ObserversTuple}, - state::{HasClientPerfMonitor, HasFeedbackStates, HasMetadata}, + state::{HasClientPerfMonitor, HasMetadata, HasNamedMetadata}, Error, }; +/// The prefix of the metadata names +pub const MAPFEEDBACK_PREFIX: &str = "mapfeedback_metadata_"; + /// 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; @@ -272,71 +272,44 @@ impl MapNoveltiesMetadata { } /// The state of [`MapFeedback`] -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(bound = "T: serde::de::DeserializeOwned")] -pub struct MapFeedbackState +#[derive(Default, Serialize, Deserialize, Clone, Debug)] +#[serde(bound = "T: DeserializeOwned")] +pub struct MapFeedbackMetadata where T: Default + Copy + 'static + Serialize, { /// Contains information about untouched entries pub history_map: Vec, - /// Name identifier of this instance - pub name: String, } -impl FeedbackState for MapFeedbackState -where - T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, -{ - fn reset(&mut self) -> Result<(), Error> { - self.history_map.iter_mut().for_each(|x| *x = T::default()); - Ok(()) - } -} +crate::impl_serdeany!( + MapFeedbackMetadata, + ,,,,,,,,,,, +); -impl Named for MapFeedbackState +impl MapFeedbackMetadata where - T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, + T: Default + Copy + 'static + Serialize + DeserializeOwned, { - #[inline] - fn name(&self) -> &str { - self.name.as_str() - } -} - -impl MapFeedbackState -where - T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned, -{ - /// Create new `MapFeedbackState` + /// Create new `MapFeedbackMetadata` #[must_use] - pub fn new(name: &'static str, map_size: usize) -> Self { + pub fn new(map_size: usize) -> Self { Self { history_map: vec![T::default(); map_size], - name: name.to_string(), } } - /// Create new `MapFeedbackState` for the observer type. - pub fn with_observer(map_observer: &O) -> Self - where - O: MapObserver, - T: PartialEq + Debug, - { - Self { - history_map: vec![map_observer.initial(); map_observer.len()], - name: map_observer.name().to_string(), - } - } - - /// Create new `MapFeedbackState` using a name and a map. + /// Create new `MapFeedbackMetadata` using a name and a map. /// The map can be shared. #[must_use] - pub fn with_history_map(name: &'static str, history_map: Vec) -> Self { - Self { - history_map, - name: name.to_string(), - } + pub fn with_history_map(history_map: Vec) -> Self { + Self { history_map } + } + + /// Reset the map + pub fn reset(&mut self) -> Result<(), Error> { + self.history_map.iter_mut().for_each(|x| *x = T::default()); + Ok(()) } } @@ -344,12 +317,12 @@ where #[derive(Clone, Debug)] pub struct MapFeedback where - T: PartialEq + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, + T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug, R: Reducer, O: MapObserver, for<'it> O: AsRefIterator<'it, Item = T>, N: IsNovel, - S: HasFeedbackStates, + S: HasNamedMetadata, { /// Indexes used in the last observation indexes: Option>, @@ -365,14 +338,19 @@ where impl Feedback for MapFeedback where - T: PartialEq + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, + T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug, R: Reducer, O: MapObserver, for<'it> O: AsRefIterator<'it, Item = T>, N: IsNovel, I: Input, - S: HasFeedbackStates + HasClientPerfMonitor + Debug, + S: HasNamedMetadata + HasClientPerfMonitor + Debug, { + fn init_state(&mut self, state: &mut S) -> Result<(), Error> { + state.add_named_metadata(MapFeedbackMetadata::::default(), &self.name); + Ok(()) + } + #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, @@ -393,11 +371,14 @@ where let initial = observer.initial(); let map_state = state - .feedback_states_mut() - .match_name_mut::>(&self.name) + .named_metadata_mut() + .get_mut::>(&self.name) .unwrap(); + if map_state.history_map.len() < observer.len() { + map_state.history_map.resize(observer.len(), T::default()); + } - assert!(size <= map_state.history_map.len(), "The size of the associated map observer cannot exceed the size of the history map of the feedback. If you are running multiple instances of slightly different fuzzers (e.g. one with ASan and another without) synchronized using LLMP please check the `configuration` field of the LLMP manager."); + // assert!(size <= map_state.history_map.len(), "The size of the associated map observer cannot exceed the size of the history map of the feedback. If you are running multiple instances of slightly different fuzzers (e.g. one with ASan and another without) synchronized using LLMP please check the `configuration` field of the LLMP manager."); assert!(size <= observer.len()); @@ -471,12 +452,12 @@ where impl Named for MapFeedback where - T: PartialEq + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, + T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug, R: Reducer, N: IsNovel, O: MapObserver, for<'it> O: AsRefIterator<'it, Item = T>, - S: HasFeedbackStates, + S: HasNamedMetadata, { #[inline] fn name(&self) -> &str { @@ -484,22 +465,37 @@ where } } -impl MapFeedback +impl HasObserverName for MapFeedback where - T: PartialEq + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, + T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug, R: Reducer, N: IsNovel, O: MapObserver, for<'it> O: AsRefIterator<'it, Item = T>, - S: HasFeedbackStates, + S: HasNamedMetadata, +{ + #[inline] + fn observer_name(&self) -> &str { + self.observer_name.as_str() + } +} + +impl MapFeedback +where + T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug, + R: Reducer, + N: IsNovel, + O: MapObserver, + for<'it> O: AsRefIterator<'it, Item = T>, + S: HasNamedMetadata, { /// Create new `MapFeedback` #[must_use] - pub fn new(feedback_state: &MapFeedbackState, map_observer: &O) -> Self { + pub fn new(map_observer: &O) -> Self { Self { indexes: None, novelties: None, - name: feedback_state.name().to_string(), + name: MAPFEEDBACK_PREFIX.to_string() + map_observer.name(), observer_name: map_observer.name().to_string(), phantom: PhantomData, } @@ -507,16 +503,11 @@ where /// Create new `MapFeedback` specifying if it must track indexes of used entries and/or novelties #[must_use] - pub fn new_tracking( - feedback_state: &MapFeedbackState, - map_observer: &O, - track_indexes: bool, - track_novelties: bool, - ) -> Self { + pub fn new_tracking(map_observer: &O, track_indexes: bool, track_novelties: bool) -> Self { Self { indexes: if track_indexes { Some(vec![]) } else { None }, novelties: if track_novelties { Some(vec![]) } else { None }, - name: feedback_state.name().to_string(), + name: MAPFEEDBACK_PREFIX.to_string() + map_observer.name(), observer_name: map_observer.name().to_string(), phantom: PhantomData, } @@ -673,10 +664,303 @@ mod tests { } } +/// `MapFeedback` Python bindings +#[cfg(feature = "python")] +pub mod pybind { + use crate::bolts::{tuples::Named, AsMutIterator, AsRefIterator, HasLen}; + use crate::observers::{map::OwnedMapObserver, MapObserver, Observer}; + use crate::Error; + use pyo3::prelude::*; + use serde::{Deserialize, Serialize}; + use std::slice::{Iter, IterMut}; + + macro_rules! define_python_map_observer { + ($struct_name:ident, $py_name:tt, $struct_name_trait:ident, $py_name_trait:tt, $datatype:ty, $wrapper_name: ident) => { + #[pyclass(unsendable, name = $py_name)] + #[derive(Serialize, Deserialize, Debug, Clone)] + /// Python class for OwnedMapObserver (i.e. StdMapObserver with owned map) + pub struct $struct_name { + /// Rust wrapped OwnedMapObserver object + pub inner: OwnedMapObserver<$datatype>, + } + + #[pymethods] + impl $struct_name { + #[new] + fn new(name: String, map: Vec<$datatype>) -> Self { + Self { + //TODO: Not leak memory + inner: OwnedMapObserver::new(Box::leak(name.into_boxed_str()), map), + } + } + } + + #[derive(Serialize, Deserialize, Debug, Clone)] + enum $wrapper_name { + Owned($struct_name), + } + + // Should not be exposed to user + #[pyclass(unsendable, name = $py_name_trait)] + #[derive(Serialize, Deserialize, Debug, Clone)] + /// MapObserver + Observer Trait binding + pub struct $struct_name_trait { + pub wrapper: $wrapper_name, + } + + impl $struct_name_trait { + fn unwrap(&self) -> &impl MapObserver { + unsafe { + match &self.wrapper { + $wrapper_name::Owned(py_wrapper) => &py_wrapper.inner, + } + } + } + + fn unwrap_mut(&mut self) -> &mut impl MapObserver { + unsafe { + match &mut self.wrapper { + $wrapper_name::Owned(py_wrapper) => &mut py_wrapper.inner, + } + } + } + + fn upcast(&self) -> &impl Observer { + unsafe { + match &self.wrapper { + $wrapper_name::Owned(py_wrapper) => &py_wrapper.inner, + } + } + } + + fn upcast_mut(&mut self) -> &mut impl Observer { + unsafe { + match &mut self.wrapper { + $wrapper_name::Owned(py_wrapper) => &mut py_wrapper.inner, + } + } + } + } + + #[pymethods] + impl $struct_name_trait { + #[staticmethod] + fn new_from_owned(owned_map: $struct_name) -> Self { + Self { + wrapper: $wrapper_name::Owned(owned_map), + } + } + } + + impl<'it> AsRefIterator<'it> for $struct_name_trait { + type Item = $datatype; + type IntoIter = Iter<'it, $datatype>; + + fn as_ref_iter(&'it self) -> Self::IntoIter { + match &self.wrapper { + $wrapper_name::Owned(py_wrapper) => py_wrapper.inner.as_ref_iter(), + } + } + } + + impl<'it> AsMutIterator<'it> for $struct_name_trait { + type Item = $datatype; + type IntoIter = IterMut<'it, $datatype>; + + fn as_mut_iter(&'it mut self) -> Self::IntoIter { + match &mut self.wrapper { + $wrapper_name::Owned(py_wrapper) => py_wrapper.inner.as_mut_iter(), + } + } + } + + impl MapObserver for $struct_name_trait { + type Entry = $datatype; + + #[inline] + fn get(&self, idx: usize) -> &$datatype { + match &self.wrapper { + $wrapper_name::Owned(py_wrapper) => &py_wrapper.inner.get(idx), + } + } + + #[inline] + fn get_mut(&mut self, idx: usize) -> &mut $datatype { + match &mut self.wrapper { + $wrapper_name::Owned(py_wrapper) => py_wrapper.inner.get_mut(idx), + } + } + + #[inline] + fn usable_count(&self) -> usize { + match &self.wrapper { + $wrapper_name::Owned(py_wrapper) => py_wrapper.wrapper.usable_count(), + } + } + + fn hash(&self) -> u64 { + match &self.wrapper { + $wrapper_name::Owned(py_wrapper) => py_wrapper.inner.hash(), + } + } + + #[inline] + fn initial(&self) -> $datatype { + match &self.wrapper { + $wrapper_name::Owned(py_wrapper) => py_wrapper.inner.initial(), + } + } + + #[inline] + fn initial_mut(&mut self) -> &mut $datatype { + match &mut self.wrapper { + $wrapper_name::Owned(py_wrapper) => py_wrapper.inner.initial_mut(), + } + } + + #[inline] + fn set_initial(&mut self, initial: $datatype) { + match &mut self.wrapper { + $wrapper_name::Owned(py_wrapper) => { + py_wrapper.inner.set_initial(initial); + } + } + } + + fn to_vec(&self) -> Vec<$datatype> { + match &self.wrapper { + $wrapper_name::Owned(py_wrapper) => py_wrapper.inner.to_vec(), + } + } + } + + impl Named for $struct_name_trait { + #[inline] + fn name(&self) -> &str { + match &self.wrapper { + $wrapper_name::Owned(py_wrapper) => py_wrapper.inner.name(), + } + } + } + + impl HasLen for $struct_name_trait { + #[inline] + fn len(&self) -> usize { + match &self.wrapper { + $wrapper_name::Owned(py_wrapper) => py_wrapper.inner.len(), + } + } + } + + impl Observer for $struct_name_trait + where + Self: MapObserver, + { + #[inline] + fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { + match &mut self.wrapper { + $wrapper_name::Owned(py_wrapper) => { + py_wrapper.inner.pre_exec(_state, _input) + } + } + } + } + }; + } + + define_python_map_observer!( + PythonOwnedMapObserverI8, + "OwnedMapObserverI8", + PythonMapObserverI8, + "MapObserverI8", + i8, + PythonMapObserverWrapperI8 + ); + define_python_map_observer!( + PythonOwnedMapObserverI16, + "OwnedMapObserverI16", + PythonMapObserverI16, + "MapObserverI16", + i16, + PythonMapObserverWrapperI16 + ); + define_python_map_observer!( + PythonOwnedMapObserverI32, + "OwnedMapObserverI32", + PythonMapObserverI32, + "MapObserverI32", + i32, + PythonMapObserverWrapperI32 + ); + define_python_map_observer!( + PythonOwnedMapObserverI64, + "OwnedMapObserverI64", + PythonMapObserverI64, + "MapObserverI64", + i64, + PythonMapObserverWrapperI64 + ); + + define_python_map_observer!( + PythonOwnedMapObserverU8, + "OwnedMapObserverU8", + PythonMapObserverU8, + "MapObserverU8", + u8, + PythonMapObserverWrapperU8 + ); + define_python_map_observer!( + PythonOwnedMapObserverU16, + "OwnedMapObserverU16", + PythonMapObserverU16, + "MapObserverU16", + u16, + PythonMapObserverWrapperU16 + ); + define_python_map_observer!( + PythonOwnedMapObserverU32, + "OwnedMapObserverU32", + PythonMapObserverU32, + "MapObserverU32", + u32, + PythonMapObserverWrapperU32 + ); + define_python_map_observer!( + PythonOwnedMapObserverU64, + "OwnedMapObserverU64", + PythonMapObserverU64, + "MapObserverU64", + u64, + PythonMapObserverWrapperU64 + ); + + /// Register the classes to the python module + pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + Ok(()) + } +} + #[cfg(feature = "python")] /// Map Feedback Python bindings pub mod pybind { - use crate::feedbacks::map::{MapFeedbackState, MaxMapFeedback}; + use crate::feedbacks::map::{MapFeedbackMetadata, MaxMapFeedback}; use crate::inputs::BytesInput; use pyo3::prelude::*; @@ -688,10 +972,10 @@ pub mod pybind { #[pyclass(unsendable, name = $map_feedback_state_py_name)] #[derive(Clone, Debug)] - /// Python class for MapFeedbackState + /// Python class for MapFeedbackMetadata pub struct $map_feedback_state_struct_name { - /// Rust wrapped MapFeedbackState object - pub map_feedback_state: MapFeedbackState<$datatype>, + /// Rust wrapped MapFeedbackMetadata object + pub map_feedback_state: MapFeedbackMetadata<$datatype>, } #[pymethods] @@ -699,7 +983,7 @@ pub mod pybind { #[staticmethod] fn with_observer(py_observer: &$map_observer_name) -> Self { Self { - map_feedback_state: MapFeedbackState::with_observer(py_observer), + map_feedback_state: MapFeedbackMetadata::with_observer(py_observer), } } } @@ -740,8 +1024,8 @@ pub mod pybind { } define_python_map_feedback!( - PythonMapFeedbackStateI8, - "MapFeedbackStateI8", + PythonMapFeedbackMetadataI8, + "MapFeedbackMetadataI8", PythonMaxMapFeedbackI8, "MaxMapFeedbackI8", i8, @@ -750,8 +1034,8 @@ pub mod pybind { ); define_python_map_feedback!( - PythonMapFeedbackStateI16, - "MapFeedbackStateI16", + PythonMapFeedbackMetadataI16, + "MapFeedbackMetadataI16", PythonMaxMapFeedbackI16, "MaxMapFeedbackI16", i16, @@ -759,8 +1043,8 @@ pub mod pybind { MyStdStateI16 ); define_python_map_feedback!( - PythonMapFeedbackStateI32, - "MapFeedbackStateI32", + PythonMapFeedbackMetadataI32, + "MapFeedbackMetadataI32", PythonMaxMapFeedbackI32, "MaxMapFeedbackI32", i32, @@ -768,8 +1052,8 @@ pub mod pybind { MyStdStateI32 ); define_python_map_feedback!( - PythonMapFeedbackStateI64, - "MapFeedbackStateI64", + PythonMapFeedbackMetadataI64, + "MapFeedbackMetadataI64", PythonMaxMapFeedbackI64, "MaxMapFeedbackI64", i64, @@ -778,8 +1062,8 @@ pub mod pybind { ); define_python_map_feedback!( - PythonMapFeedbackStateU8, - "MapFeedbackStateU8", + PythonMapFeedbackMetadataU8, + "MapFeedbackMetadataU8", PythonMaxMapFeedbackU8, "MaxMapFeedbackU8", u8, @@ -788,8 +1072,8 @@ pub mod pybind { ); define_python_map_feedback!( - PythonMapFeedbackStateU16, - "MapFeedbackStateU16", + PythonMapFeedbackMetadataU16, + "MapFeedbackMetadataU16", PythonMaxMapFeedbackU16, "MaxMapFeedbackU16", u16, @@ -797,8 +1081,8 @@ pub mod pybind { MyStdStateU16 ); define_python_map_feedback!( - PythonMapFeedbackStateU32, - "MapFeedbackStateU32", + PythonMapFeedbackMetadataU32, + "MapFeedbackMetadataU32", PythonMaxMapFeedbackU32, "MaxMapFeedbackU32", u32, @@ -806,8 +1090,8 @@ pub mod pybind { MyStdStateU32 ); define_python_map_feedback!( - PythonMapFeedbackStateU64, - "MapFeedbackStateU64", + PythonMapFeedbackMetadataU64, + "MapFeedbackMetadataU64", PythonMaxMapFeedbackU64, "MaxMapFeedbackU64", u64, @@ -817,15 +1101,15 @@ pub mod pybind { /// Register the classes to the python module pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; m.add_class::()?; m.add_class::()?; diff --git a/libafl/src/feedbacks/mod.rs b/libafl/src/feedbacks/mod.rs index 57d6c4925c..741cb66a6c 100644 --- a/libafl/src/feedbacks/mod.rs +++ b/libafl/src/feedbacks/mod.rs @@ -16,7 +16,7 @@ pub mod new_hash_feedback; #[cfg(feature = "std")] pub use new_hash_feedback::NewHashFeedback; #[cfg(feature = "std")] -pub use new_hash_feedback::NewHashFeedbackState; +pub use new_hash_feedback::NewHashFeedbackMetadata; #[cfg(feature = "nautilus")] pub mod nautilus; @@ -27,7 +27,7 @@ use alloc::string::{String, ToString}; use serde::{Deserialize, Serialize}; use crate::{ - bolts::tuples::{MatchName, Named}, + bolts::tuples::Named, corpus::Testcase, events::EventFirer, executors::ExitKind, @@ -51,6 +51,12 @@ where I: Input, S: HasClientPerfMonitor, { + /// Initializes the feedback state. + /// This method is called after that the `State` is created. + fn init_state(&mut self, _state: &mut S) -> Result<(), Error> { + Ok(()) + } + /// `is_interesting ` return if an input is worth the addition to the corpus #[allow(clippy::wrong_self_convention)] fn is_interesting( @@ -116,36 +122,10 @@ where } } -/// [`FeedbackState`] is the data associated with a [`Feedback`] that must persist as part -/// of the fuzzer State -pub trait FeedbackState: Named + Serialize + serde::de::DeserializeOwned + Debug { - /// Reset the internal state - fn reset(&mut self) -> Result<(), Error> { - Ok(()) - } -} - -/// A haskell-style tuple of feedback states -pub trait FeedbackStatesTuple: MatchName + Serialize + serde::de::DeserializeOwned + Debug { - /// Resets all the feedback states of the tuple - fn reset_all(&mut self) -> Result<(), Error>; -} - -impl FeedbackStatesTuple for () { - fn reset_all(&mut self) -> Result<(), Error> { - Ok(()) - } -} - -impl FeedbackStatesTuple for (Head, Tail) -where - Head: FeedbackState, - Tail: FeedbackStatesTuple, -{ - fn reset_all(&mut self) -> Result<(), Error> { - self.0.reset()?; - self.1.reset_all() - } +/// Has an associated observer name (mostly used to retrieve the observer with `MatchName` from an `ObserverTuple`) +pub trait HasObserverName { + /// The name associated with the observer + fn observer_name(&self) -> &str; } /// A combined feedback consisting of multiple [`Feedback`]s @@ -207,6 +187,12 @@ where I: Input, S: HasClientPerfMonitor + Debug, { + fn init_state(&mut self, state: &mut S) -> Result<(), Error> { + self.first.init_state(state)?; + self.second.init_state(state)?; + Ok(()) + } + #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, @@ -596,6 +582,10 @@ where I: Input, S: HasClientPerfMonitor, { + fn init_state(&mut self, state: &mut S) -> Result<(), Error> { + self.first.init_state(state) + } + #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, @@ -984,3 +974,177 @@ where } } } + +/// The [`ConstFeedback`] reports the same value, always. +/// It can be used to enable or disable feedback results through composition. +#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)] +pub enum ConstFeedback { + /// Always returns `true` + True, + /// Alsways returns `false` + False, +} + +impl Feedback for ConstFeedback +where + I: Input, + S: HasClientPerfMonitor, +{ + #[inline] + #[allow(clippy::wrong_self_convention)] + fn is_interesting( + &mut self, + _state: &mut S, + _manager: &mut EM, + _input: &I, + _observers: &OT, + _exit_kind: &ExitKind, + ) -> Result + where + EM: EventFirer, + OT: ObserversTuple, + { + Ok(match self { + ConstFeedback::True => true, + ConstFeedback::False => false, + }) + } +} + +impl Named for ConstFeedback { + #[inline] + fn name(&self) -> &str { + "ConstFeedback" + } +} + +impl ConstFeedback { + /// Creates a new [`ConstFeedback`] from the given boolean + #[must_use] + pub fn new(val: bool) -> Self { + Self::from(val) + } +} + +impl From for ConstFeedback { + fn from(val: bool) -> Self { + if val { + Self::True + } else { + Self::False + } + } +} + +/// `Feedback` Python bindings +#[cfg(feature = "python")] +pub mod pybind { + use crate::inputs::BytesInput; + use crate::{ + bolts::tuples::Named, corpus::Testcase, events::EventFirer, executors::ExitKind, + feedbacks::Feedback, observers::ObserversTuple, Error, + }; + use pyo3::prelude::*; + + macro_rules! define_python_feedback { + ($struct_name_trait:ident, $py_name_trait:tt, $wrapper_name: ident, $my_std_state_type_name: ident) => { + use crate::observers::map::pybind::PythonMaxMapFeedbackI8; + use crate::state::pybind::$my_std_state_type_name; + + #[derive(Debug)] + enum $wrapper_name { + MaxMapI8(*mut PythonMaxMapFeedbackI8), + } + + #[pyclass(unsendable, name = $py_name_trait)] + #[derive(Debug)] + /// Observer Trait binding + pub struct $struct_name_trait { + pub wrapper: $wrapper_name, + } + + impl $struct_name_trait { + fn unwrap(&self) -> &impl Feedback { + unsafe { + match self.wrapper { + $wrapper_name::MaxMapI8(py_wrapper) => &(*py_wrapper).upcast(), + } + } + } + + fn unwrap_mut( + &mut self, + ) -> &mut impl Feedback { + unsafe { + match self.wrapper { + $wrapper_name::MaxMapI8(py_wrapper) => &mut (*py_wrapper).upcast_mut(), + } + } + } + } + + #[pymethods] + impl $struct_name_trait { + #[staticmethod] + fn new_map(map_feedback: &mut PythonMaxMapFeedbackI8) -> Self { + Self { + observer: $wrapper_name::MaxMapI8(map_feedback), + } + } + } + + impl Named for $struct_name_trait { + fn name(&self) -> &str { + self.unwrap().name() + } + } + + impl Feedback for $struct_name_trait { + fn init_state(&mut self, state: &mut S) -> Result<(), Error> { + self.unwrap_mut().init_state(state) + } + + fn is_interesting( + &mut self, + state: &mut S, + manager: &mut EM, + input: &I, + observers: &OT, + exit_kind: &ExitKind, + ) -> Result + where + EM: EventFirer, + OT: ObserversTuple, + { + self.unwrap_mut() + .is_interesting(state, manager, input, observers, exit_kind) + } + + fn append_metadata( + &mut self, + state: &mut S, + testcase: &mut Testcase, + ) -> Result<(), Error> { + self.unwrap_mut().append_metadata(state, testcase) + } + + fn discard_metadata(&mut self, state: &mut S, input: &I) -> Result<(), Error> { + self.unwrap_mut().discard_metadata(state, input) + } + } + }; + } + + define_python_feedback!( + PythonFeedback, + "Feedback", + PythonFeedbackWrapper, + PythonStdState, + ); + + /// Register the classes to the python module + pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { + m.add_class::()?; + Ok(()) + } +} diff --git a/libafl/src/feedbacks/new_hash_feedback.rs b/libafl/src/feedbacks/new_hash_feedback.rs index dc4f1da76b..ecaa1f27b0 100644 --- a/libafl/src/feedbacks/new_hash_feedback.rs +++ b/libafl/src/feedbacks/new_hash_feedback.rs @@ -1,98 +1,64 @@ //! The ``NewHashFeedback`` uses the backtrace hash and a hashset to only keep novel cases -use std::{fmt::Debug, hash::Hash, marker::PhantomData}; +use std::{fmt::Debug, marker::PhantomData}; use hashbrown::HashSet; -use num_traits::PrimInt; use serde::{Deserialize, Serialize}; use crate::{ - bolts::tuples::{MatchName, Named}, + bolts::tuples::Named, events::EventFirer, executors::ExitKind, - feedbacks::{Feedback, FeedbackState}, + feedbacks::{Feedback, HasObserverName}, inputs::Input, observers::{ObserverWithHashField, ObserversTuple}, - state::{HasClientPerfMonitor, HasFeedbackStates}, + state::{HasClientPerfMonitor, HasNamedMetadata}, Error, }; +/// The prefix of the metadata names +pub const NEWHASHFEEDBACK_PREFIX: &str = "newhashfeedback_metadata_"; + /// A state that implements this trait has a hash set pub trait HashSetState { /// creates a new instance with a specific hashset - fn with_hash_set(name: &'static str, hash_set: HashSet) -> Self; + fn with_hash_set(hash_set: HashSet) -> Self; /// updates the `hash_set` with the given value fn update_hash_set(&mut self, value: T) -> Result; } /// The state of [`NewHashFeedback`] -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(bound = "T: serde::de::DeserializeOwned")] -pub struct NewHashFeedbackState -where - T: PrimInt + Default + Copy + 'static + Serialize + Hash + Debug, -{ +#[derive(Default, Serialize, Deserialize, Clone, Debug)] +pub struct NewHashFeedbackMetadata { /// Contains information about untouched entries - pub hash_set: HashSet, - /// Name identifier of this instance - pub name: String, + pub hash_set: HashSet, } -impl FeedbackState for NewHashFeedbackState -where - T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Hash + Debug, -{ - fn reset(&mut self) -> Result<(), Error> { +#[rustfmt::skip] +crate::impl_serdeany!(NewHashFeedbackMetadata); + +impl NewHashFeedbackMetadata { + /// Create a new [`NewHashFeedbackMetadata`] + #[must_use] + pub fn new() -> Self { + Self::default() + } + + /// Reset the internal state + pub fn reset(&mut self) -> Result<(), Error> { self.hash_set.clear(); Ok(()) } } -impl Named for NewHashFeedbackState -where - T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Hash + Debug, -{ - #[inline] - fn name(&self) -> &str { - self.name.as_str() - } -} - -impl NewHashFeedbackState -where - T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Hash + Debug, -{ - /// Create a new [`NewHashFeedbackState`] +impl HashSetState for NewHashFeedbackMetadata { + /// Create new [`NewHashFeedbackMetadata`] using a name and a hash set. #[must_use] - pub fn new(name: &'static str) -> Self { - Self { - hash_set: HashSet::::new(), - name: name.to_string(), - } + fn with_hash_set(hash_set: HashSet) -> Self { + Self { hash_set } } - /// Create a new [`NewHashFeedbackState`] for an observer that implements [`ObserverWithHashField`] - pub fn with_observer(backtrace_observer: &(impl ObserverWithHashField + Named)) -> Self { - Self { - hash_set: HashSet::::new(), - name: backtrace_observer.name().to_string(), - } - } -} -impl HashSetState for NewHashFeedbackState -where - T: PrimInt + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Hash + Debug, -{ - /// Create new [`NewHashFeedbackState`] using a name and a hash set. - #[must_use] - fn with_hash_set(name: &'static str, hash_set: HashSet) -> Self { - Self { - hash_set, - name: name.to_string(), - } - } - - fn update_hash_set(&mut self, value: T) -> Result { + fn update_hash_set(&mut self, value: u64) -> Result { let r = self.hash_set.insert(value); // println!("Got r={}, the hashset is {:?}", r, &self.hash_set); Ok(r) @@ -102,7 +68,7 @@ where /// A [`NewHashFeedback`] maintains a hashset of already seen stacktraces and considers interesting unseen ones #[derive(Serialize, Deserialize, Clone, Debug)] pub struct NewHashFeedback { - feedback_name: String, + name: String, observer_name: String, o_type: PhantomData, } @@ -110,13 +76,18 @@ pub struct NewHashFeedback { impl Feedback for NewHashFeedback where I: Input, - S: HasClientPerfMonitor + HasFeedbackStates, + S: HasClientPerfMonitor + HasNamedMetadata, O: ObserverWithHashField + Named + Debug, { + fn init_state(&mut self, state: &mut S) -> Result<(), Error> { + state.add_named_metadata(NewHashFeedbackMetadata::default(), &self.name); + Ok(()) + } + #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, - _state: &mut S, + state: &mut S, _manager: &mut EM, _input: &I, observers: &OT, @@ -130,9 +101,9 @@ where .match_name::(&self.observer_name) .expect("A NewHashFeedback needs a BacktraceObserver"); - let backtrace_state = _state - .feedback_states_mut() - .match_name_mut::>(&self.observer_name) + let backtrace_state = state + .named_metadata_mut() + .get_mut::(&self.name) .unwrap(); match observer.hash() { @@ -153,7 +124,14 @@ where impl Named for NewHashFeedback { #[inline] fn name(&self) -> &str { - &self.feedback_name + &self.name + } +} + +impl HasObserverName for NewHashFeedback { + #[inline] + fn observer_name(&self) -> &str { + &self.observer_name } } @@ -161,12 +139,12 @@ impl NewHashFeedback where O: ObserverWithHashField + Named + Debug, { - /// Returns a new [`NewHashFeedback`]. Carefull, it's recommended to use `new_with_observer` + /// Returns a new [`NewHashFeedback`]. /// Setting an observer name that doesn't exist would eventually trigger a panic. #[must_use] - pub fn new(feedback_name: &str, observer_name: &str) -> Self { + pub fn with_names(name: &str, observer_name: &str) -> Self { Self { - feedback_name: feedback_name.to_string(), + name: name.to_string(), observer_name: observer_name.to_string(), o_type: PhantomData, } @@ -174,9 +152,9 @@ where /// Returns a new [`NewHashFeedback`]. #[must_use] - pub fn new_with_observer(feedback_name: &str, observer: &O) -> Self { + pub fn new(observer: &O) -> Self { Self { - feedback_name: feedback_name.to_string(), + name: NEWHASHFEEDBACK_PREFIX.to_string() + observer.name(), observer_name: observer.name().to_string(), o_type: PhantomData, } diff --git a/libafl/src/feedbacks/owned.rs b/libafl/src/feedbacks/owned.rs new file mode 100644 index 0000000000..6549164940 --- /dev/null +++ b/libafl/src/feedbacks/owned.rs @@ -0,0 +1,188 @@ +//! A dynamic collection of owned FeedbackStates + +use alloc::{boxed::Box, vec::Vec}; + +use crate::{ + bolts::anymap::AsAny, + feedbacks::{FeedbackState, FeedbackStateTuple}, + Error, +}; + +/// Combine `FeedbackState` and `AsAny` +pub trait AnyFeedbackState: FeedbackState + AsAny {} + +/// An owned list of `FeedbackState` trait objects +#[derive(Default)] +#[allow(missing_debug_implementations)] +pub struct FeedbackStatesOwnedList { + /// The named trait objects map + pub list: Vec>, +} + +impl FeedbackStatesTuple for FeedbackStatesOwnedList { + fn perform_all( + &mut self, + fuzzer: &mut Z, + executor: &mut E, + state: &mut S, + manager: &mut EM, + corpus_idx: usize, + ) -> Result<(), Error> { + for s in &mut self.list { + s.perform(fuzzer, executor, state, manager, corpus_idx)?; + } + Ok(()) + } +} + +impl FeedbackStatesOwnedList { + /// Create a new instance + #[must_use] + pub fn new(list: Vec>) -> Self { + Self { list } + } +} + +#[cfg(feature = "python")] +/// `FeedbackStatesOwnedList` Python bindings +pub mod pybind { + use crate::stages::owned::FeedbackStatesOwnedList; + use pyo3::prelude::*; + + macro_rules! define_python_stage_owned_list { + ($struct_name:ident, $py_name:tt, $my_std_state_type_name: ident, $my_std_fuzzer_type_name: ident, $event_manager_name: ident, + $executor_name: ident, $stage_name: ident) => { + use crate::events::pybind::$event_manager_name; + use crate::executors::pybind::$executor_name; + use crate::fuzzer::pybind::$my_std_fuzzer_type_name; + use crate::stages::pybind::$stage_name; + use crate::state::pybind::$my_std_state_type_name; + #[pyclass(unsendable, name = $py_name)] + + /// Python class for FeedbackStatesOwnedList + #[allow(missing_debug_implementations)] + pub struct $struct_name { + /// Rust wrapped FeedbackStatesOwnedList object + pub stages_owned_list: FeedbackStatesOwnedList< + $executor_name, + $event_manager_name, + $my_std_state_type_name, + $my_std_fuzzer_type_name, + >, + } + + #[pymethods] + impl $struct_name { + //TODO: Add new from list + #[new] + fn new(stage: &$stage_name) -> Self { + // TODO: Be safe + unsafe { + Self { + stages_owned_list: FeedbackStatesOwnedList { + list: vec![Box::new(std::mem::transmute_copy::< + $stage_name, + $stage_name, + >(stage))], + }, + } + } + } + } + }; + } + + define_python_stage_owned_list!( + PythonFeedbackStatesOwnedListI8, + "FeedbackStatesOwnedListI8", + MyStdStateI8, + MyStdFuzzerI8, + PythonEventManagerI8, + PythonExecutorI8, + PythonFeedbackStateI8 + ); + + define_python_stage_owned_list!( + PythonFeedbackStatesOwnedListI16, + "FeedbackStatesOwnedListI16", + MyStdStateI16, + MyStdFuzzerI16, + PythonEventManagerI16, + PythonExecutorI16, + PythonFeedbackStateI16 + ); + + define_python_stage_owned_list!( + PythonFeedbackStatesOwnedListI32, + "FeedbackStatesOwnedListI32", + MyStdStateI32, + MyStdFuzzerI32, + PythonEventManagerI32, + PythonExecutorI32, + PythonFeedbackStateI32 + ); + + define_python_stage_owned_list!( + PythonFeedbackStatesOwnedListI64, + "FeedbackStatesOwnedListI64", + MyStdStateI64, + MyStdFuzzerI64, + PythonEventManagerI64, + PythonExecutorI64, + PythonFeedbackStateI64 + ); + + define_python_stage_owned_list!( + PythonFeedbackStatesOwnedListU8, + "FeedbackStatesOwnedListU8", + MyStdStateU8, + MyStdFuzzerU8, + PythonEventManagerU8, + PythonExecutorU8, + PythonFeedbackStateU8 + ); + + define_python_stage_owned_list!( + PythonFeedbackStatesOwnedListU16, + "FeedbackStatesOwnedListU16", + MyStdStateU16, + MyStdFuzzerU16, + PythonEventManagerU16, + PythonExecutorU16, + PythonFeedbackStateU16 + ); + + define_python_stage_owned_list!( + PythonFeedbackStatesOwnedListU32, + "FeedbackStatesOwnedListU32", + MyStdStateU32, + MyStdFuzzerU32, + PythonEventManagerU32, + PythonExecutorU32, + PythonFeedbackStateU32 + ); + + define_python_stage_owned_list!( + PythonFeedbackStatesOwnedListU64, + "FeedbackStatesOwnedListU64", + MyStdStateU64, + MyStdFuzzerU64, + PythonEventManagerU64, + PythonExecutorU64, + PythonFeedbackStateU64 + ); + + /// Register the classes to the python module + pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + Ok(()) + } +} diff --git a/libafl/src/lib.rs b/libafl/src/lib.rs index 93ce650f43..8327ad0602 100644 --- a/libafl/src/lib.rs +++ b/libafl/src/lib.rs @@ -70,10 +70,10 @@ Welcome to `LibAFL` )] #[macro_use] -extern crate alloc; +pub extern crate alloc; #[macro_use] extern crate static_assertions; -#[cfg(feature = "std")] +#[cfg(feature = "ctor")] pub use ctor::ctor; // Re-export derive(SerdeAny) @@ -407,8 +407,10 @@ mod tests { rand, corpus, InMemoryCorpus::::new(), - tuple_list!(), - ); + &mut (), + &mut (), + ) + .unwrap(); let monitor = SimpleMonitor::new(|s| { println!("{}", s); @@ -440,7 +442,6 @@ mod tests { let state_serialized = postcard::to_allocvec(&state).unwrap(); let state_deserialized: StdState< InMemoryCorpus, - (), BytesInput, StdRand, InMemoryCorpus, diff --git a/libafl/src/mutators/mutations.rs b/libafl/src/mutators/mutations.rs index f915d89649..ead2d508f7 100644 --- a/libafl/src/mutators/mutations.rs +++ b/libafl/src/mutators/mutations.rs @@ -1230,7 +1230,8 @@ mod tests { .add(BytesInput::new(vec![0x42; 0x1337]).into()) .unwrap(); - let mut state = StdState::new(rand, corpus, InMemoryCorpus::new(), ()); + let mut state = + StdState::new(rand, corpus, InMemoryCorpus::new(), &mut (), &mut ()).unwrap(); let mut mutations = test_mutations(); for _ in 0..2 { diff --git a/libafl/src/mutators/scheduled.rs b/libafl/src/mutators/scheduled.rs index 49f1002fd1..b937d9e2cf 100644 --- a/libafl/src/mutators/scheduled.rs +++ b/libafl/src/mutators/scheduled.rs @@ -447,7 +447,8 @@ mod tests { let testcase = corpus.get(0).expect("Corpus did not contain entries"); let mut input = testcase.borrow_mut().load_input().unwrap().clone(); - let mut state = StdState::new(rand, corpus, InMemoryCorpus::new(), ()); + let mut state = + StdState::new(rand, corpus, InMemoryCorpus::new(), &mut (), &mut ()).unwrap(); rand.set_seed(5); @@ -474,7 +475,8 @@ mod tests { let mut input = testcase.borrow_mut().load_input().unwrap().clone(); let input_prior = input.clone(); - let mut state = StdState::new(rand, corpus, InMemoryCorpus::new(), ()); + let mut state = + StdState::new(rand, corpus, InMemoryCorpus::new(), &mut (), &mut ()).unwrap(); let mut havoc = StdScheduledMutator::new(havoc_mutations()); diff --git a/libafl/src/observers/map.rs b/libafl/src/observers/map.rs index 9f5a172f32..5cc8de407a 100644 --- a/libafl/src/observers/map.rs +++ b/libafl/src/observers/map.rs @@ -1487,6 +1487,7 @@ where } } } + /// `MapObserver` Python bindings #[cfg(feature = "python")] pub mod pybind { @@ -1504,7 +1505,7 @@ pub mod pybind { /// Python class for OwnedMapObserver (i.e. StdMapObserver with owned map) pub struct $struct_name { /// Rust wrapped OwnedMapObserver object - pub owned_map_observer: OwnedMapObserver<$datatype>, + pub inner: OwnedMapObserver<$datatype>, } #[pymethods] @@ -1513,10 +1514,7 @@ pub mod pybind { fn new(name: String, map: Vec<$datatype>) -> Self { Self { //TODO: Not leak memory - owned_map_observer: OwnedMapObserver::new( - Box::leak(name.into_boxed_str()), - map, - ), + inner: OwnedMapObserver::new(Box::leak(name.into_boxed_str()), map), } } } @@ -1531,15 +1529,49 @@ pub mod pybind { #[derive(Serialize, Deserialize, Debug, Clone)] /// MapObserver + Observer Trait binding pub struct $struct_name_trait { - map_observer: $wrapper_name, + pub wrapper: $wrapper_name, + } + + impl $struct_name_trait { + fn unwrap(&self) -> &impl MapObserver { + unsafe { + match &self.wrapper { + $wrapper_name::Owned(py_wrapper) => &py_wrapper.inner, + } + } + } + + fn unwrap_mut(&mut self) -> &mut impl MapObserver { + unsafe { + match &mut self.wrapper { + $wrapper_name::Owned(py_wrapper) => &mut py_wrapper.inner, + } + } + } + + fn upcast(&self) -> &impl Observer { + unsafe { + match &self.wrapper { + $wrapper_name::Owned(py_wrapper) => &py_wrapper.inner, + } + } + } + + fn upcast_mut(&mut self) -> &mut impl Observer { + unsafe { + match &mut self.wrapper { + $wrapper_name::Owned(py_wrapper) => &mut py_wrapper.inner, + } + } + } } #[pymethods] impl $struct_name_trait { #[staticmethod] - fn new_from_owned(owned_map_observer: $struct_name) -> Self { + fn new_from_owned(owned_map: $struct_name) -> Self { Self { - map_observer: $wrapper_name::Owned(owned_map_observer), + wrapper: $wrapper_name::Owned(owned_map), } } } @@ -1549,10 +1581,8 @@ pub mod pybind { type IntoIter = Iter<'it, $datatype>; fn as_ref_iter(&'it self) -> Self::IntoIter { - match &self.map_observer { - $wrapper_name::Owned(map_observer) => { - map_observer.owned_map_observer.as_ref_iter() - } + match &self.wrapper { + $wrapper_name::Owned(py_wrapper) => py_wrapper.inner.as_ref_iter(), } } } @@ -1562,10 +1592,8 @@ pub mod pybind { type IntoIter = IterMut<'it, $datatype>; fn as_mut_iter(&'it mut self) -> Self::IntoIter { - match &mut self.map_observer { - $wrapper_name::Owned(map_observer) => { - map_observer.owned_map_observer.as_mut_iter() - } + match &mut self.wrapper { + $wrapper_name::Owned(py_wrapper) => py_wrapper.inner.as_mut_iter(), } } } @@ -1575,71 +1603,57 @@ pub mod pybind { #[inline] fn get(&self, idx: usize) -> &$datatype { - match &self.map_observer { - $wrapper_name::Owned(map_observer) => { - &map_observer.owned_map_observer.get(idx) - } + match &self.wrapper { + $wrapper_name::Owned(py_wrapper) => &py_wrapper.inner.get(idx), } } #[inline] fn get_mut(&mut self, idx: usize) -> &mut $datatype { - match &mut self.map_observer { - $wrapper_name::Owned(map_observer) => { - map_observer.owned_map_observer.get_mut(idx) - } + match &mut self.wrapper { + $wrapper_name::Owned(py_wrapper) => py_wrapper.inner.get_mut(idx), } } #[inline] fn usable_count(&self) -> usize { - match &self.map_observer { - $wrapper_name::Owned(map_observer) => { - map_observer.owned_map_observer.usable_count() - } + match &self.wrapper { + $wrapper_name::Owned(py_wrapper) => py_wrapper.wrapper.usable_count(), } } fn hash(&self) -> u64 { - match &self.map_observer { - $wrapper_name::Owned(map_observer) => { - map_observer.owned_map_observer.hash() - } + match &self.wrapper { + $wrapper_name::Owned(py_wrapper) => py_wrapper.inner.hash(), } } #[inline] fn initial(&self) -> $datatype { - match &self.map_observer { - $wrapper_name::Owned(map_observer) => { - map_observer.owned_map_observer.initial() - } + match &self.wrapper { + $wrapper_name::Owned(py_wrapper) => py_wrapper.inner.initial(), } } #[inline] fn initial_mut(&mut self) -> &mut $datatype { - match &mut self.map_observer { - $wrapper_name::Owned(map_observer) => { - map_observer.owned_map_observer.initial_mut() - } + match &mut self.wrapper { + $wrapper_name::Owned(py_wrapper) => py_wrapper.inner.initial_mut(), } } #[inline] fn set_initial(&mut self, initial: $datatype) { - match &mut self.map_observer { - $wrapper_name::Owned(map_observer) => { - map_observer.owned_map_observer.set_initial(initial); + match &mut self.wrapper { + $wrapper_name::Owned(py_wrapper) => { + py_wrapper.inner.set_initial(initial); } } } fn to_vec(&self) -> Vec<$datatype> { - match &self.map_observer { - $wrapper_name::Owned(map_observer) => { - map_observer.owned_map_observer.to_vec() - } + match &self.wrapper { + $wrapper_name::Owned(py_wrapper) => py_wrapper.inner.to_vec(), } } } @@ -1647,10 +1661,8 @@ pub mod pybind { impl Named for $struct_name_trait { #[inline] fn name(&self) -> &str { - match &self.map_observer { - $wrapper_name::Owned(map_observer) => { - map_observer.owned_map_observer.name() - } + match &self.wrapper { + $wrapper_name::Owned(py_wrapper) => py_wrapper.inner.name(), } } } @@ -1658,8 +1670,8 @@ pub mod pybind { impl HasLen for $struct_name_trait { #[inline] fn len(&self) -> usize { - match &self.map_observer { - $wrapper_name::Owned(map_observer) => map_observer.owned_map_observer.len(), + match &self.wrapper { + $wrapper_name::Owned(py_wrapper) => py_wrapper.inner.len(), } } } @@ -1670,9 +1682,9 @@ pub mod pybind { { #[inline] fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { - match &mut self.map_observer { - $wrapper_name::Owned(map_observer) => { - map_observer.owned_map_observer.pre_exec(_state, _input) + match &mut self.wrapper { + $wrapper_name::Owned(py_wrapper) => { + py_wrapper.inner.pre_exec(_state, _input) } } } diff --git a/libafl/src/observers/mod.rs b/libafl/src/observers/mod.rs index 5c3fc1ef94..f26099156d 100644 --- a/libafl/src/observers/mod.rs +++ b/libafl/src/observers/mod.rs @@ -290,6 +290,125 @@ where } } +/// `Observer` Python bindings +#[cfg(feature = "python")] +pub mod pybind { + use crate::bolts::tuples::Named; + use crate::executors::ExitKind; + use crate::inputs::BytesInput; + use crate::observers::Observer; + use crate::Error; + use pyo3::prelude::*; + + macro_rules! define_python_observer { + ($struct_name_trait:ident, $py_name_trait:tt, $wrapper_name: ident, $my_std_state_type_name: ident) => { + use crate::observers::map::pybind::PythonMapObserverI8; + use crate::state::pybind::$my_std_state_type_name; + + #[derive(Debug)] + enum $wrapper_name { + MapI8(*mut PythonMapObserverI8), + } + + #[pyclass(unsendable, name = $py_name_trait)] + #[derive(Debug)] + /// Observer Trait binding + pub struct $struct_name_trait { + pub wrapper: $wrapper_name, + } + + impl $struct_name_trait { + fn unwrap(&self) -> &impl Observer { + unsafe { + match self.wrapper { + $wrapper_name::MapI8(py_wrapper) => &(*py_wrapper).upcast(), + } + } + } + + fn unwrap_mut( + &mut self, + ) -> &mut impl Observer { + unsafe { + match self.wrapper { + $wrapper_name::MapI8(py_wrapper) => &mut (*py_wrapper).upcast_mut(), + } + } + } + } + + #[pymethods] + impl $struct_name_trait { + #[staticmethod] + fn new_map(map_observer: &mut PythonMapObserverI8) -> Self { + Self { + observer: $wrapper_name::MapI8(map_observer), + } + } + } + + impl Named for $struct_name_trait { + fn name(&self) -> &str { + self.unwrap().name() + } + } + + impl Observer for $struct_name_trait { + fn flush(&mut self) -> Result<(), Error> { + self.unwrap_mut().flush() + } + + fn pre_exec( + &mut self, + state: &mut $my_std_state_type_name, + input: &BytesInput, + ) -> Result<(), Error> { + self.unwrap_mut().pre_exec(state, input) + } + + fn post_exec( + &mut self, + state: &mut $my_std_state_type_name, + input: &BytesInput, + exit_kind: &ExitKind, + ) -> Result<(), Error> { + self.unwrap_mut().post_exec(state, input, exit_kind) + } + + fn pre_exec_child( + &mut self, + state: &mut $my_std_state_type_name, + input: &BytesInput, + ) -> Result<(), Error> { + self.unwrap_mut().pre_exec(state, input) + } + + fn post_exec_child( + &mut self, + state: &mut $my_std_state_type_name, + input: &BytesInput, + exit_kind: &ExitKind, + ) -> Result<(), Error> { + self.unwrap_mut().post_exec_child(state, input, exit_kind) + } + } + }; + } + + define_python_observer!( + PythonObserver, + "Observer", + PythonObserverWrapper, + PythonStdState, + ); + + /// Register the classes to the python module + pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { + m.add_class::()?; + Ok(()) + } +} + #[cfg(feature = "std")] #[cfg(test)] mod tests { diff --git a/libafl/src/schedulers/probabilistic_sampling.rs b/libafl/src/schedulers/probabilistic_sampling.rs index f4a1bfb5b3..547ec5d73d 100644 --- a/libafl/src/schedulers/probabilistic_sampling.rs +++ b/libafl/src/schedulers/probabilistic_sampling.rs @@ -188,7 +188,8 @@ mod tests { let idx1 = corpus.add(t1).unwrap(); let idx2 = corpus.add(t2).unwrap(); - let mut state = StdState::new(rand, corpus, InMemoryCorpus::new(), ()); + let mut state = + StdState::new(rand, corpus, InMemoryCorpus::new(), &mut (), &mut ()).unwrap(); scheduler.on_add(state.borrow_mut(), idx1).unwrap(); scheduler.on_add(state.borrow_mut(), idx2).unwrap(); let next_idx1 = scheduler.next(&mut state).unwrap(); diff --git a/libafl/src/schedulers/queue.rs b/libafl/src/schedulers/queue.rs index f238162f3c..61605c84aa 100644 --- a/libafl/src/schedulers/queue.rs +++ b/libafl/src/schedulers/queue.rs @@ -79,7 +79,7 @@ mod tests { OnDiskCorpus::::new(PathBuf::from("target/.test/fancy/objective/path")) .unwrap(); - let mut state = StdState::new(rand, q, objective_q, ()); + let mut state = StdState::new(rand, q, objective_q, &mut (), &mut ()).unwrap(); let next_idx = scheduler.next(&mut state).unwrap(); let filename = state diff --git a/libafl/src/stages/calibrate.rs b/libafl/src/stages/calibrate.rs index 6e94b67b33..145a875af3 100644 --- a/libafl/src/stages/calibrate.rs +++ b/libafl/src/stages/calibrate.rs @@ -1,18 +1,20 @@ //! The calibration stage. The fuzzer measures the average exec time and the bitmap size. use crate::{ - bolts::current_time, - bolts::tuples::MatchName, + bolts::{current_time, tuples::Named, AsRefIterator}, corpus::{Corpus, SchedulerTestcaseMetaData}, events::{EventFirer, LogSeverity}, executors::{Executor, ExitKind, HasObservers}, - feedbacks::MapFeedbackState, + feedbacks::{ + map::{IsNovel, MapFeedback, MapFeedbackMetadata, Reducer}, + HasObserverName, + }, fuzzer::Evaluator, inputs::Input, observers::{MapObserver, ObserversTuple}, schedulers::powersched::SchedulerMetadata, stages::Stage, - state::{HasClientPerfMonitor, HasCorpus, HasFeedbackStates, HasMetadata}, + state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasNamedMetadata}, Error, }; use alloc::string::{String, ToString}; @@ -27,9 +29,10 @@ where I: Input, O: MapObserver, OT: ObserversTuple, - S: HasCorpus + HasMetadata, + S: HasCorpus + HasMetadata + HasNamedMetadata, { map_observer_name: String, + map_name: String, stage_max: usize, phantom: PhantomData<(I, O, OT, S)>, } @@ -45,7 +48,7 @@ where O: MapObserver, for<'de> ::Entry: Serialize + Deserialize<'de> + 'static, OT: ObserversTuple, - S: HasCorpus + HasMetadata + HasFeedbackStates + HasClientPerfMonitor, + S: HasCorpus + HasMetadata + HasClientPerfMonitor + HasNamedMetadata, Z: Evaluator, { #[inline] @@ -147,8 +150,8 @@ where .to_vec(); let history_map = &mut state - .feedback_states_mut() - .match_name_mut::>(&self.map_observer_name) + .named_metadata_mut() + .get_mut::>(&self.map_name) .unwrap() .history_map; @@ -222,12 +225,21 @@ where I: Input, O: MapObserver, OT: ObserversTuple, - S: HasCorpus + HasMetadata, + S: HasCorpus + HasMetadata + HasNamedMetadata, { /// Create a new [`CalibrationStage`]. - pub fn new(map_observer_name: &O) -> Self { + #[must_use] + pub fn new(map_feedback: &MapFeedback) -> Self + where + O::Entry: + PartialEq + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, + R: Reducer, + for<'it> O: AsRefIterator<'it, Item = O::Entry>, + N: IsNovel, + { Self { - map_observer_name: map_observer_name.name().to_string(), + map_observer_name: map_feedback.observer_name().to_string(), + map_name: map_feedback.name().to_string(), stage_max: CAL_STAGE_START, phantom: PhantomData, } diff --git a/libafl/src/state/mod.rs b/libafl/src/state/mod.rs index 011f7b10bc..ec3a061414 100644 --- a/libafl/src/state/mod.rs +++ b/libafl/src/state/mod.rs @@ -11,11 +11,11 @@ use std::{ use crate::{ bolts::{ rands::Rand, - serdeany::{SerdeAny, SerdeAnyMap}, + serdeany::{NamedSerdeAnyMap, SerdeAny, SerdeAnyMap}, }, corpus::Corpus, events::{Event, EventFirer, LogSeverity}, - feedbacks::FeedbackStatesTuple, + feedbacks::Feedback, fuzzer::{Evaluator, ExecuteInputResult}, generators::Generator, inputs::Input, @@ -110,15 +110,30 @@ pub trait HasMetadata { } } -/// Trait for elements offering a feedback -pub trait HasFeedbackStates { - /// The associated feedback type implementing [`FeedbackStatesTuple`]. - type FeedbackStates: FeedbackStatesTuple; - /// The feedback states - fn feedback_states(&self) -> &Self::FeedbackStates; +/// Trait for elements offering named metadata +pub trait HasNamedMetadata { + /// A map, storing all metadata + fn named_metadata(&self) -> &NamedSerdeAnyMap; + /// A map, storing all metadata (mutable) + fn named_metadata_mut(&mut self) -> &mut NamedSerdeAnyMap; - /// The feedback states (mutable) - fn feedback_states_mut(&mut self) -> &mut Self::FeedbackStates; + /// Add a metadata to the metadata map + #[inline] + fn add_named_metadata(&mut self, meta: M, name: &str) + where + M: SerdeAny, + { + self.named_metadata_mut().insert(meta, name); + } + + /// Check for a metadata + #[inline] + fn has_named_metadata(&self, name: &str) -> bool + where + M: SerdeAny, + { + self.named_metadata().contains::(name) + } } /// Trait for the execution counter @@ -141,13 +156,12 @@ pub trait HasStartTime { /// The state a fuzz run. #[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(bound = "FT: serde::de::DeserializeOwned")] -pub struct StdState +#[serde(bound = "C: serde::Serialize + for<'a> serde::Deserialize<'a>")] +pub struct StdState where C: Corpus, I: Input, R: Rand, - FT: FeedbackStatesTuple, SC: Corpus, { /// RNG instance @@ -158,12 +172,12 @@ where start_time: Duration, /// The corpus corpus: C, - /// States of the feedback used to evaluate an input - feedback_states: FT, // Solutions corpus solutions: SC, /// Metadata stored for this state by one of the components metadata: SerdeAnyMap, + /// Metadata stored with names + named_metadata: NamedSerdeAnyMap, /// MaxSize testcase size for mutators that appreciate it max_size: usize, /// The stability of the current fuzzing process @@ -176,22 +190,20 @@ where phantom: PhantomData, } -impl State for StdState +impl State for StdState where C: Corpus, I: Input, R: Rand, - FT: FeedbackStatesTuple, SC: Corpus, { } -impl HasRand for StdState +impl HasRand for StdState where C: Corpus, I: Input, R: Rand, - FT: FeedbackStatesTuple, SC: Corpus, { type Rand = R; @@ -209,12 +221,11 @@ where } } -impl HasCorpus for StdState +impl HasCorpus for StdState where C: Corpus, I: Input, R: Rand, - FT: FeedbackStatesTuple, SC: Corpus, { type Corpus = C; @@ -232,12 +243,11 @@ where } } -impl HasSolutions for StdState +impl HasSolutions for StdState where C: Corpus, I: Input, R: Rand, - FT: FeedbackStatesTuple, SC: Corpus, { type Solutions = SC; @@ -255,12 +265,11 @@ where } } -impl HasMetadata for StdState +impl HasMetadata for StdState where C: Corpus, I: Input, R: Rand, - FT: FeedbackStatesTuple, SC: Corpus, { /// Get all the metadata into an [`hashbrown::HashMap`] @@ -276,35 +285,31 @@ where } } -impl HasFeedbackStates for StdState +impl HasNamedMetadata for StdState where C: Corpus, I: Input, R: Rand, - FT: FeedbackStatesTuple, SC: Corpus, { - type FeedbackStates = FT; - - /// The feedback states + /// Get all the metadata into an [`hashbrown::HashMap`] #[inline] - fn feedback_states(&self) -> &FT { - &self.feedback_states + fn named_metadata(&self) -> &NamedSerdeAnyMap { + &self.named_metadata } - /// The feedback states (mutable) + /// Get all the metadata into an [`hashbrown::HashMap`] (mutable) #[inline] - fn feedback_states_mut(&mut self) -> &mut FT { - &mut self.feedback_states + fn named_metadata_mut(&mut self) -> &mut NamedSerdeAnyMap { + &mut self.named_metadata } } -impl HasExecutions for StdState +impl HasExecutions for StdState where C: Corpus, I: Input, R: Rand, - FT: FeedbackStatesTuple, SC: Corpus, { /// The executions counter @@ -320,12 +325,11 @@ where } } -impl HasMaxSize for StdState +impl HasMaxSize for StdState where C: Corpus, I: Input, R: Rand, - FT: FeedbackStatesTuple, SC: Corpus, { fn max_size(&self) -> usize { @@ -337,12 +341,11 @@ where } } -impl HasStartTime for StdState +impl HasStartTime for StdState where C: Corpus, I: Input, R: Rand, - FT: FeedbackStatesTuple, SC: Corpus, { /// The starting time @@ -359,12 +362,11 @@ where } #[cfg(feature = "std")] -impl StdState +impl StdState where C: Corpus, I: Input, R: Rand, - FT: FeedbackStatesTuple, SC: Corpus, { /// Loads inputs from a directory. @@ -480,12 +482,11 @@ where } } -impl StdState +impl StdState where C: Corpus, I: Input, R: Rand, - FT: FeedbackStatesTuple, SC: Corpus, { fn generate_initial_internal( @@ -561,31 +562,43 @@ where } /// Creates a new `State`, taking ownership of all of the individual components during fuzzing. - pub fn new(rand: R, corpus: C, solutions: SC, feedback_states: FT) -> Self { - Self { + pub fn new( + rand: R, + corpus: C, + solutions: SC, + feedback: &mut F, + objective: &mut O, + ) -> Result + where + F: Feedback, + O: Feedback, + { + let mut state = Self { rand, executions: 0, stability: None, start_time: Duration::from_millis(0), metadata: SerdeAnyMap::default(), + named_metadata: NamedSerdeAnyMap::default(), corpus, - feedback_states, solutions, max_size: DEFAULT_MAX_SIZE, #[cfg(feature = "introspection")] introspection_monitor: ClientPerfMonitor::new(), phantom: PhantomData, - } + }; + feedback.init_state(&mut state)?; + objective.init_state(&mut state)?; + Ok(state) } } #[cfg(feature = "introspection")] -impl HasClientPerfMonitor for StdState +impl HasClientPerfMonitor for StdState where C: Corpus, I: Input, R: Rand, - FT: FeedbackStatesTuple, SC: Corpus, { fn introspection_monitor(&self) -> &ClientPerfMonitor { @@ -610,12 +623,11 @@ where } #[cfg(not(feature = "introspection"))] -impl HasClientPerfMonitor for StdState +impl HasClientPerfMonitor for StdState where C: Corpus, I: Input, R: Rand, - FT: FeedbackStatesTuple, SC: Corpus, { fn introspection_monitor(&self) -> &ClientPerfMonitor { @@ -645,28 +657,20 @@ pub mod pybind { use crate::bolts::rands::pybind::PythonRand; use crate::bolts::tuples::tuple_list; use crate::corpus::pybind::PythonCorpus; - use crate::feedbacks::map::MapFeedbackState; + use crate::feedbacks::pybind::PythonFeedback; use crate::inputs::BytesInput; use crate::state::StdState; use pyo3::prelude::*; macro_rules! define_python_state { - ($type_name:ident, $struct_name:ident, $py_name:tt, $datatype:ty, $py_map_feedback_state_name:ident, $event_manager_name: ident, - $fuzzer_name: ident, $executor_name: ident, $rand_printable_generator: ident) => { + ($type_name:ident, $struct_name:ident, $py_name:tt) => { use crate::events::pybind::$event_manager_name; use crate::executors::pybind::$executor_name; - use crate::feedbacks::map::pybind::$py_map_feedback_state_name; use crate::fuzzer::pybind::$fuzzer_name; use crate::generators::pybind::$rand_printable_generator; /// `StdState` with fixed generics - pub type $type_name = StdState< - PythonCorpus, - (MapFeedbackState<$datatype>, ()), - BytesInput, - PythonRand, - PythonCorpus, - >; + pub type $type_name = StdState; #[pyclass(unsendable, name = $py_name)] #[derive(Debug)] @@ -683,24 +687,20 @@ pub mod pybind { py_rand: PythonRand, corpus: PythonCorpus, solutions: PythonCorpus, - py_map_feedback_state: $py_map_feedback_state_name, + feedback: &mut PythonFeedback, + objective: &mut PythonFeedback, ) -> Self { Self { - std_state: StdState::new( - py_rand, - corpus, - solutions, - tuple_list!(py_map_feedback_state.map_feedback_state), - ), + std_state: StdState::new(py_rand, corpus, solutions, feedback, objective), } } fn generate_initial_inputs( &mut self, - py_fuzzer: &mut $fuzzer_name, - py_executor: &mut $executor_name, - py_generator: &mut $rand_printable_generator, - py_mgr: &mut $event_manager_name, + py_fuzzer: &mut PythonFuzzer, + py_executor: &mut PythonExecutor, + py_generator: &mut PythonGenerator, + py_mgr: &mut PythonEventManager, num: usize, ) { self.std_state @@ -717,109 +717,11 @@ pub mod pybind { }; } - define_python_state!( - MyStdStateI8, - PythonStdStateI8, - "StdStateI8", - i8, - PythonMapFeedbackStateI8, - PythonEventManagerI8, - PythonStdFuzzerI8, - PythonExecutorI8, - PythonRandPrintablesGeneratorI8 - ); - - define_python_state!( - MyStdStateI16, - PythonStdStateI16, - "StdStateI16", - i16, - PythonMapFeedbackStateI16, - PythonEventManagerI16, - PythonStdFuzzerI16, - PythonExecutorI16, - PythonRandPrintablesGeneratorI16 - ); - - define_python_state!( - MyStdStateI32, - PythonStdStateI32, - "StdStateI32", - i32, - PythonMapFeedbackStateI32, - PythonEventManagerI32, - PythonStdFuzzerI32, - PythonExecutorI32, - PythonRandPrintablesGeneratorI32 - ); - - define_python_state!( - MyStdStateI64, - PythonStdStateI64, - "StdStateI64", - i64, - PythonMapFeedbackStateI64, - PythonEventManagerI64, - PythonStdFuzzerI64, - PythonExecutorI64, - PythonRandPrintablesGeneratorI64 - ); - define_python_state!( - MyStdStateU8, - PythonStdStateU8, - "StdStateU8", - u8, - PythonMapFeedbackStateU8, - PythonEventManagerU8, - PythonStdFuzzerU8, - PythonExecutorU8, - PythonRandPrintablesGeneratorU8 - ); - define_python_state!( - MyStdStateU16, - PythonStdStateU16, - "StdStateU16", - u16, - PythonMapFeedbackStateU16, - PythonEventManagerU16, - PythonStdFuzzerU16, - PythonExecutorU16, - PythonRandPrintablesGeneratorU16 - ); - define_python_state!( - MyStdStateU32, - PythonStdStateU32, - "StdStateU32", - u32, - PythonMapFeedbackStateU32, - PythonEventManagerU32, - PythonStdFuzzerU32, - PythonExecutorU32, - PythonRandPrintablesGeneratorU32 - ); - define_python_state!( - MyStdStateU64, - PythonStdStateU64, - "StdStateU64", - u64, - PythonMapFeedbackStateU64, - PythonEventManagerU64, - PythonStdFuzzerU64, - PythonExecutorU64, - PythonRandPrintablesGeneratorU64 - ); + define_python_state!(PythonStdState, PythonStdStateWrapper, "StdState",); /// Register the classes to the python module pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; + m.add_class::()?; Ok(()) } } diff --git a/libafl_concolic/symcc_runtime/symcc b/libafl_concolic/symcc_runtime/symcc index 5cccc33456..45cde0269a 160000 --- a/libafl_concolic/symcc_runtime/symcc +++ b/libafl_concolic/symcc_runtime/symcc @@ -1 +1 @@ -Subproject commit 5cccc33456c48ad83008eb618e7da5d005c72d89 +Subproject commit 45cde0269ae22aef4cca2e1fb98c3b24f7bb2984 diff --git a/libafl_sugar/src/forkserver.rs b/libafl_sugar/src/forkserver.rs index 7e9d423d06..075ae7b466 100644 --- a/libafl_sugar/src/forkserver.rs +++ b/libafl_sugar/src/forkserver.rs @@ -17,7 +17,7 @@ use libafl::{ events::{EventConfig, EventRestarter, LlmpRestartingEventManager}, executors::{forkserver::ForkserverExecutorBuilder, TimeoutForkserverExecutor}, feedback_or, feedback_or_fast, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, fuzzer::{Fuzzer, StdFuzzer}, generators::RandBytesGenerator, monitors::MultiMonitor, @@ -111,7 +111,7 @@ impl<'a, const MAP_SIZE: usize> ForkserverBytesCoverageSugar<'a, MAP_SIZE> { let monitor = MultiMonitor::new(|s| println!("{}", s)); - let mut run_client = |state: Option>, + let mut run_client = |state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _, _, _>, _core_id| { // Coverage map shared between target and fuzzer @@ -130,20 +130,17 @@ impl<'a, const MAP_SIZE: usize> ForkserverBytesCoverageSugar<'a, MAP_SIZE> { // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); - // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( + let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + MaxMapFeedback::new_tracking(&edges_observer, true, false), // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); // A feedback to choose if an input is a solution or not - let objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); + let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -155,10 +152,10 @@ impl<'a, const MAP_SIZE: usize> ForkserverBytesCoverageSugar<'a, MAP_SIZE> { // Corpus in which we store solutions (crashes in this example), // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(crashes.clone()).unwrap(), - // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), + &mut feedback, + &mut objective, ) + .unwrap() }); // Create a dictionary if not existing diff --git a/libafl_sugar/src/inmemory.rs b/libafl_sugar/src/inmemory.rs index 0433268d08..aceafbaf3d 100644 --- a/libafl_sugar/src/inmemory.rs +++ b/libafl_sugar/src/inmemory.rs @@ -19,7 +19,7 @@ use libafl::{ events::{EventConfig, EventRestarter, LlmpRestartingEventManager}, executors::{inprocess::InProcessExecutor, ExitKind, ShadowExecutor, TimeoutExecutor}, feedback_or, feedback_or_fast, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, fuzzer::{Fuzzer, StdFuzzer}, generators::RandBytesGenerator, inputs::{BytesInput, HasTargetBytes}, @@ -138,7 +138,7 @@ where let monitor = MultiMonitor::new(|s| println!("{}", s)); - let mut run_client = |state: Option>, + let mut run_client = |state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _, _, _>, _core_id| { // Create an observation channel using the coverage map @@ -151,20 +151,17 @@ where let cmplog = unsafe { &mut CMPLOG_MAP }; let cmplog_observer = CmpLogObserver::new("cmplog", cmplog, true); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); - // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( + let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + MaxMapFeedback::new_tracking(&edges_observer, true, false), // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); // A feedback to choose if an input is a solution or not - let objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); + let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -176,10 +173,10 @@ where // Corpus in which we store solutions (crashes in this example), // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(crashes.clone()).unwrap(), - // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), + &mut feedback, + &mut objective, ) + .unwrap() }); // Create a dictionary if not existing diff --git a/libafl_sugar/src/qemu.rs b/libafl_sugar/src/qemu.rs index 85b55c8aa2..dfa0f42a6e 100644 --- a/libafl_sugar/src/qemu.rs +++ b/libafl_sugar/src/qemu.rs @@ -18,7 +18,7 @@ use libafl::{ events::{EventConfig, EventRestarter, LlmpRestartingEventManager}, executors::{ExitKind, ShadowExecutor, TimeoutExecutor}, feedback_or, feedback_or_fast, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, + feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, fuzzer::{Fuzzer, StdFuzzer}, generators::RandBytesGenerator, inputs::{BytesInput, HasTargetBytes}, @@ -141,7 +141,7 @@ where let monitor = MultiMonitor::new(|s| println!("{}", s)); - let mut run_client = |state: Option>, + let mut run_client = |state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _, _, _>, _core_id| { // Create an observation channel using the coverage map @@ -157,20 +157,17 @@ where let cmplog = unsafe { &mut cmplog::CMPLOG_MAP }; let cmplog_observer = CmpLogObserver::new("cmplog", cmplog, true); - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); - // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( + let mut feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + MaxMapFeedback::new_tracking(&edges_observer, true, false), // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); // A feedback to choose if an input is a solution or not - let objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); + let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); // If not restarting, create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -182,10 +179,10 @@ where // Corpus in which we store solutions (crashes in this example), // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(crashes.clone()).unwrap(), - // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), + &mut feedback, + &mut objective, ) + .unwrap() }); // Create a dictionary if not existing