Implement CanTrack tracking enforcement through rust types (#1886)

* sample implementation of tracking enforcement (incomplete)

* helpful compiler output

* make it look like a real compiler output

* ensure that the macro may be used outside of libafl

* separate index/novelty tracking funcs

* default const generic values so that we don't need to change this everywhere

* fix tests

* rollback unnecessary specification of stdmapobserver

* register metadata in doc tests

* doc fixes

* doc cleanup

* doc cleanup 2

* reduce implementor overhead to zero

* renaming/docs fixes

* asref isn't reflexive??

* generalization stage updates

* add better documentation about require_{indices,novelties}_tracking

* remaining generic updates

* round one CI pass (knowingly introduces breaking changes)

* typo

* round 2 clippy

* rollback: libafl_frida changes

* fmt

* moar porting

* fix remaining fuzzers

* fix windows build, maybe

* fixup libafl_libfuzzer

* fmt nighlty all the things

* attempt to fix some broken additions

* fix fmt

* oops

* fix new invocation

* minimizer scheduler fixes

* fix accounting

* rename

* fix

* Fix build

* Sort generics

* Move more generics into the right place

* Rename A -> C

* Fix test

* Fix test some more

* Fix doc some more

* critical formatting

* More A->C

* CanTrack harder

---------

Co-authored-by: Dominik Maier <dmnk@google.com>
This commit is contained in:
Addison Crump 2024-04-12 18:33:52 +02:00 committed by GitHub
parent ec935bf95f
commit 3d702f403b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
61 changed files with 1183 additions and 515 deletions

View File

@ -117,7 +117,7 @@ For bugs, feel free to open issues or contact us directly. Thank you for your su
Even though we will gladly assist you in finishing up your PR, try to Even though we will gladly assist you in finishing up your PR, try to
- keep all the crates compiling with *stable* rust (hide the eventual non-stable code under [`cfg`s](https://github.com/AFLplusplus/LibAFL/blob/main/libafl/build.rs#L26)) - keep all the crates compiling with *stable* rust (hide the eventual non-stable code under [`cfg`s](https://github.com/AFLplusplus/LibAFL/blob/main/libafl/build.rs#L26))
- run `cargo fmt` on your code before pushing - run `cargo +nightly fmt` on your code before pushing
- check the output of `cargo clippy --all` or `./clippy.sh` - check the output of `cargo clippy --all` or `./clippy.sh`
- run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. - run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code.

View File

@ -15,7 +15,7 @@ use libafl::{
GrimoireRandomDeleteMutator, GrimoireRecursiveReplacementMutator, GrimoireRandomDeleteMutator, GrimoireRecursiveReplacementMutator,
GrimoireStringReplacementMutator, Tokens, GrimoireStringReplacementMutator, Tokens,
}, },
observers::StdMapObserver, observers::{CanTrack, StdMapObserver},
schedulers::QueueScheduler, schedulers::QueueScheduler,
stages::{mutational::StdMutationalStage, GeneralizationStage}, stages::{mutational::StdMutationalStage, GeneralizationStage},
state::StdState, state::StdState,
@ -83,9 +83,11 @@ pub fn main() {
}; };
// Create an observation channel using the signals map // Create an observation channel using the signals map
let observer = unsafe { StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()) }; let observer = unsafe {
StdMapObserver::from_mut_ptr("signals", SIGNALS_PTR, SIGNALS.len()).track_novelties()
};
// Feedback to rate the interestingness of an input // Feedback to rate the interestingness of an input
let mut feedback = MaxMapFeedback::tracking(&observer, false, true); let mut feedback = MaxMapFeedback::new(&observer);
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not
let mut objective = CrashFeedback::new(); let mut objective = CrashFeedback::new();

View File

@ -19,6 +19,9 @@ command = "cargo"
args = ["build" , "--profile", "${PROFILE}", "--bin", "${FUZZER_NAME}"] args = ["build" , "--profile", "${PROFILE}", "--bin", "${FUZZER_NAME}"]
dependencies = [ "cc" ] dependencies = [ "cc" ]
[tasks.build]
alias = "fuzzer"
# Run the fuzzer # Run the fuzzer
[tasks.run] [tasks.run]
command = "${CARGO_TARGET_DIR}/${PROFILE_DIR}/${FUZZER_NAME}" command = "${CARGO_TARGET_DIR}/${PROFILE_DIR}/${FUZZER_NAME}"

View File

@ -54,7 +54,7 @@ pub fn main() {
// Feedback to rate the interestingness of an input // Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = MaxMapFeedback::tracking(&edges_observer, true, false); let mut feedback = MaxMapFeedback::new(&edges_observer);
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not
// We want to do the same crash deduplication that AFL does // We want to do the same crash deduplication that AFL does

View File

@ -12,7 +12,7 @@ use libafl::{
inputs::BytesInput, inputs::BytesInput,
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::{scheduled::havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens}, mutators::{scheduled::havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens},
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
@ -101,8 +101,9 @@ pub fn main() {
let shmem_buf = shmem.as_mut_slice(); let shmem_buf = shmem.as_mut_slice();
// Create an observation channel using the signals map // Create an observation channel using the signals map
let edges_observer = let edges_observer = unsafe {
unsafe { HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)) }; HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)).track_indices()
};
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -111,7 +112,7 @@ pub fn main() {
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, false), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -151,7 +152,7 @@ pub fn main() {
let mut mgr = SimpleEventManager::new(monitor); let mut mgr = SimpleEventManager::new(monitor);
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -12,7 +12,7 @@ use libafl::{
inputs::BytesInput, inputs::BytesInput,
monitors::SimpleMonitor, monitors::SimpleMonitor,
mutators::{scheduled::havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens}, mutators::{scheduled::havoc_mutations, tokens_mutations, StdScheduledMutator, Tokens},
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
@ -101,8 +101,9 @@ pub fn main() {
let shmem_buf = shmem.as_mut_slice(); let shmem_buf = shmem.as_mut_slice();
// Create an observation channel using the signals map // Create an observation channel using the signals map
let edges_observer = let edges_observer = unsafe {
unsafe { HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)) }; HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)).track_indices()
};
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -111,7 +112,7 @@ pub fn main() {
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, false), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -151,7 +152,7 @@ pub fn main() {
let mut mgr = SimpleEventManager::new(monitor); let mut mgr = SimpleEventManager::new(monitor);
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -1,9 +1,5 @@
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts //! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
//! The example harness is built for libpng. //! The example harness is built for libpng.
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
use std::{path::PathBuf, ptr::null}; use std::{path::PathBuf, ptr::null};
use frida_gum::Gum; use frida_gum::Gum;
@ -20,7 +16,7 @@ use libafl::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
token_mutations::{I2SRandReplace, Tokens}, token_mutations::{I2SRandReplace, Tokens},
}, },
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::{ShadowTracingStage, StdMutationalStage}, stages::{ShadowTracingStage, StdMutationalStage},
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
@ -39,7 +35,7 @@ use libafl_bolts::{
#[cfg(unix)] #[cfg(unix)]
use libafl_frida::asan::{ use libafl_frida::asan::{
asan_rt::AsanRuntime, asan_rt::AsanRuntime,
errors::{AsanErrorsFeedback, AsanErrorsObserver}, errors::{AsanErrorsFeedback, AsanErrorsObserver, ASAN_ERRORS},
}; };
use libafl_frida::{ use libafl_frida::{
cmplog_rt::CmpLogRuntime, cmplog_rt::CmpLogRuntime,
@ -48,6 +44,10 @@ use libafl_frida::{
helper::FridaInstrumentationHelper, helper::FridaInstrumentationHelper,
}; };
use libafl_targets::cmplog::CmpLogObserver; use libafl_targets::cmplog::CmpLogObserver;
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
pub unsafe fn lib(main: extern "C" fn(i32, *const *const u8, *const *const u8) -> i32) { pub unsafe fn lib(main: extern "C" fn(i32, *const *const u8, *const *const u8) -> i32) {
color_backtrace::install(); color_backtrace::install();
@ -104,7 +104,7 @@ unsafe fn fuzz(
let coverage = CoverageRuntime::new(); let coverage = CoverageRuntime::new();
#[cfg(unix)] #[cfg(unix)]
let asan = AsanRuntime::new(options); let asan = AsanRuntime::new(&options);
#[cfg(unix)] #[cfg(unix)]
let mut frida_helper = let mut frida_helper =
@ -118,7 +118,8 @@ unsafe fn fuzz(
"edges", "edges",
frida_helper.map_mut_ptr().unwrap(), frida_helper.map_mut_ptr().unwrap(),
MAP_SIZE, MAP_SIZE,
)); ))
.track_indices();
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -127,7 +128,7 @@ unsafe fn fuzz(
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, false), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -177,7 +178,8 @@ unsafe fn fuzz(
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler =
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
@ -233,7 +235,8 @@ unsafe fn fuzz(
"edges", "edges",
frida_helper.map_mut_ptr().unwrap(), frida_helper.map_mut_ptr().unwrap(),
MAP_SIZE, MAP_SIZE,
)); ))
.track_indices();
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -242,7 +245,7 @@ unsafe fn fuzz(
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, false), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -290,7 +293,8 @@ unsafe fn fuzz(
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler =
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
@ -361,7 +365,8 @@ unsafe fn fuzz(
"edges", "edges",
frida_helper.map_mut_ptr().unwrap(), frida_helper.map_mut_ptr().unwrap(),
MAP_SIZE, MAP_SIZE,
)); ))
.track_indices();
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -370,7 +375,7 @@ unsafe fn fuzz(
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, false), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -418,7 +423,8 @@ unsafe fn fuzz(
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler =
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -26,7 +26,7 @@ use libafl::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
token_mutations::{I2SRandReplace, Tokens}, token_mutations::{I2SRandReplace, Tokens},
}, },
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::{ShadowTracingStage, StdMutationalStage}, stages::{ShadowTracingStage, StdMutationalStage},
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
@ -113,7 +113,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
"edges", "edges",
frida_helper.map_mut_ptr().unwrap(), frida_helper.map_mut_ptr().unwrap(),
MAP_SIZE, MAP_SIZE,
)); ))
.track_indices();
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -122,7 +123,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, false), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -171,7 +172,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler =
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
@ -227,7 +229,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
"edges", "edges",
frida_helper.map_mut_ptr().unwrap(), frida_helper.map_mut_ptr().unwrap(),
MAP_SIZE, MAP_SIZE,
)); ))
.track_indices();
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -236,7 +239,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, false), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -284,7 +287,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler =
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
@ -356,7 +360,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
"edges", "edges",
frida_helper.map_mut_ptr().unwrap(), frida_helper.map_mut_ptr().unwrap(),
MAP_SIZE, MAP_SIZE,
)); ))
.track_indices();
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -365,7 +370,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, false), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -413,7 +418,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler =
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -1,9 +1,5 @@
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts //! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
//! The example harness is built for libpng. //! The example harness is built for libpng.
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
use std::path::PathBuf; use std::path::PathBuf;
use frida_gum::Gum; use frida_gum::Gum;
@ -20,7 +16,7 @@ use libafl::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
token_mutations::{I2SRandReplace, Tokens}, token_mutations::{I2SRandReplace, Tokens},
}, },
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::{ShadowTracingStage, StdMutationalStage}, stages::{ShadowTracingStage, StdMutationalStage},
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
@ -39,7 +35,7 @@ use libafl_bolts::{
#[cfg(unix)] #[cfg(unix)]
use libafl_frida::asan::{ use libafl_frida::asan::{
asan_rt::AsanRuntime, asan_rt::AsanRuntime,
errors::{AsanErrorsFeedback, AsanErrorsObserver}, errors::{AsanErrorsFeedback, AsanErrorsObserver, ASAN_ERRORS},
}; };
use libafl_frida::{ use libafl_frida::{
cmplog_rt::CmpLogRuntime, cmplog_rt::CmpLogRuntime,
@ -48,6 +44,10 @@ use libafl_frida::{
helper::FridaInstrumentationHelper, helper::FridaInstrumentationHelper,
}; };
use libafl_targets::cmplog::CmpLogObserver; use libafl_targets::cmplog::CmpLogObserver;
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
/// The main fn, usually parsing parameters, and starting the fuzzer /// The main fn, usually parsing parameters, and starting the fuzzer
pub fn main() { pub fn main() {
@ -108,7 +108,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
"edges", "edges",
frida_helper.map_mut_ptr().unwrap(), frida_helper.map_mut_ptr().unwrap(),
MAP_SIZE, MAP_SIZE,
)); ))
.track_indices();
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -117,7 +118,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, false), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -167,7 +168,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler =
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
@ -224,7 +226,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
"edges", "edges",
frida_helper.map_mut_ptr().unwrap(), frida_helper.map_mut_ptr().unwrap(),
MAP_SIZE, MAP_SIZE,
)); ))
.track_indices();
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -233,7 +236,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, false), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -281,7 +284,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler =
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
@ -352,7 +356,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
"edges", "edges",
frida_helper.map_mut_ptr().unwrap(), frida_helper.map_mut_ptr().unwrap(),
MAP_SIZE, MAP_SIZE,
)); ))
.track_indices();
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -361,7 +366,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, false), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -409,7 +414,8 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler =
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -28,7 +28,7 @@ use libafl::{
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations,
StdMOptMutator, StdScheduledMutator, Tokens, StdMOptMutator, StdScheduledMutator, Tokens,
}, },
observers::{HitcountsMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver},
schedulers::{ schedulers::{
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
}, },
@ -242,14 +242,15 @@ fn fuzz(
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
// We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges) // We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges)
let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }); let edges_observer =
HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }).track_indices();
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
let cmplog_observer = CmpLogObserver::new("cmplog", true); let cmplog_observer = CmpLogObserver::new("cmplog", true);
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); let map_feedback = MaxMapFeedback::new(&edges_observer);
let calibration = CalibrationStage::new(&map_feedback); let calibration = CalibrationStage::new(&map_feedback);
@ -307,11 +308,10 @@ fn fuzz(
let power = StdPowerMutationalStage::new(mutator); let power = StdPowerMutationalStage::new(mutator);
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( let scheduler = IndexesLenTimeMinimizerScheduler::new(
&mut state,
&edges_observer, &edges_observer,
Some(PowerSchedule::FAST), StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)),
)); );
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -31,7 +31,7 @@ use libafl::{
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations,
StdMOptMutator, StdScheduledMutator, Tokens, StdMOptMutator, StdScheduledMutator, Tokens,
}, },
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{ schedulers::{
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
}, },
@ -252,14 +252,15 @@ fn fuzz(
"edges", "edges",
OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE), OwnedMutSlice::from_raw_parts_mut(edges_map_mut_ptr(), EDGES_MAP_SIZE),
) )
}); })
.track_indices();
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
let cmplog_observer = CmpLogObserver::new("cmplog", true); let cmplog_observer = CmpLogObserver::new("cmplog", true);
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); let map_feedback = MaxMapFeedback::new(&edges_observer);
let calibration = CalibrationStage::new(&map_feedback); let calibration = CalibrationStage::new(&map_feedback);
@ -317,11 +318,10 @@ fn fuzz(
let power = StdPowerMutationalStage::new(mutator); let power = StdPowerMutationalStage::new(mutator);
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( let scheduler = IndexesLenTimeMinimizerScheduler::new(
&mut state,
&edges_observer, &edges_observer,
Some(PowerSchedule::FAST), StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)),
)); );
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -26,7 +26,7 @@ use libafl::{
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations,
StdMOptMutator, StdScheduledMutator, Tokens, StdMOptMutator, StdScheduledMutator, Tokens,
}, },
observers::{ConstMapObserver, HitcountsMapObserver, TimeObserver}, observers::{CanTrack, ConstMapObserver, HitcountsMapObserver, TimeObserver},
schedulers::{ schedulers::{
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, PowerQueueScheduler, powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, PowerQueueScheduler,
}, },
@ -242,6 +242,7 @@ fn fuzz(
"edges", "edges",
edges.as_mut_ptr(), edges.as_mut_ptr(),
)) ))
.track_indices()
}; };
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
@ -250,7 +251,7 @@ fn fuzz(
// Create an observation channel using cmplog map // Create an observation channel using cmplog map
let cmplog_observer = unsafe { CmpLogObserver::with_map_ptr("cmplog", cmplog_map_ptr, true) }; let cmplog_observer = unsafe { CmpLogObserver::with_map_ptr("cmplog", cmplog_map_ptr, true) };
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); let map_feedback = MaxMapFeedback::new(&edges_observer);
let calibration = CalibrationStage::new(&map_feedback); let calibration = CalibrationStage::new(&map_feedback);
@ -299,11 +300,10 @@ fn fuzz(
let power = StdPowerMutationalStage::new(mutator); let power = StdPowerMutationalStage::new(mutator);
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(PowerQueueScheduler::new( let scheduler = IndexesLenTimeMinimizerScheduler::new(
&mut state,
&edges_observer, &edges_observer,
PowerSchedule::FAST, PowerQueueScheduler::new(&mut state, &edges_observer, PowerSchedule::FAST),
)); );
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -21,7 +21,9 @@ use libafl::{
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations,
StdMOptMutator, StdScheduledMutator, Tokens, StdMOptMutator, StdScheduledMutator, Tokens,
}, },
observers::{HitcountsMapObserver, StdCmpValuesObserver, StdMapObserver, TimeObserver}, observers::{
CanTrack, HitcountsMapObserver, StdCmpValuesObserver, StdMapObserver, TimeObserver,
},
schedulers::{ schedulers::{
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
}, },
@ -248,13 +250,14 @@ fn fuzz(
std::env::set_var("AFL_MAP_SIZE", format!("{}", MAP_SIZE)); std::env::set_var("AFL_MAP_SIZE", format!("{}", MAP_SIZE));
// Create an observation channel using the hitcounts map of AFL++ // Create an observation channel using the hitcounts map of AFL++
let edges_observer = let edges_observer = unsafe {
unsafe { HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)) }; HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)).track_indices()
};
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); let map_feedback = MaxMapFeedback::new(&edges_observer);
let calibration = CalibrationStage::new(&map_feedback); let calibration = CalibrationStage::new(&map_feedback);
@ -300,11 +303,14 @@ fn fuzz(
let power = StdPowerMutationalStage::new(mutator); let power = StdPowerMutationalStage::new(mutator);
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( let scheduler = IndexesLenTimeMinimizerScheduler::new(
&edges_observer,
StdWeightedScheduler::with_schedule(
&mut state, &mut state,
&edges_observer, &edges_observer,
Some(PowerSchedule::EXPLORE), Some(PowerSchedule::EXPLORE),
)); ),
);
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -21,7 +21,7 @@ use libafl::{
scheduled::havoc_mutations, token_mutations::AFLppRedQueen, tokens_mutations, scheduled::havoc_mutations, token_mutations::AFLppRedQueen, tokens_mutations,
StdMOptMutator, Tokens, StdMOptMutator, Tokens,
}, },
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{ schedulers::{
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
}, },
@ -251,13 +251,14 @@ fn fuzz(
std::env::set_var("AFL_MAP_SIZE", format!("{MAP_SIZE}")); std::env::set_var("AFL_MAP_SIZE", format!("{MAP_SIZE}"));
// Create an observation channel using the hitcounts map of AFL++ // Create an observation channel using the hitcounts map of AFL++
let edges_observer = let edges_observer = unsafe {
unsafe { HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)) }; HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_buf)).track_indices()
};
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); let map_feedback = MaxMapFeedback::new(&edges_observer);
let calibration = CalibrationStage::new(&map_feedback); let calibration = CalibrationStage::new(&map_feedback);
@ -303,11 +304,14 @@ fn fuzz(
let power = StdPowerMutationalStage::new(mutator); let power = StdPowerMutationalStage::new(mutator);
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( let scheduler = IndexesLenTimeMinimizerScheduler::new(
&edges_observer,
StdWeightedScheduler::with_schedule(
&mut state, &mut state,
&edges_observer, &edges_observer,
Some(PowerSchedule::EXPLORE), Some(PowerSchedule::EXPLORE),
)); ),
);
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -25,7 +25,7 @@ use libafl::{
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations,
StdMOptMutator, StdScheduledMutator, Tokens, StdMOptMutator, StdScheduledMutator, Tokens,
}, },
observers::{HitcountsMapObserver, TimeObserver, VariableMapObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver},
schedulers::{ schedulers::{
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, PowerQueueScheduler, powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, PowerQueueScheduler,
}, },
@ -53,6 +53,7 @@ use libafl_qemu::{
elf::EasyElf, elf::EasyElf,
filter_qemu_args, filter_qemu_args,
hooks::QemuHooks, hooks::QemuHooks,
Emulator,
GuestReg, GuestReg,
//snapshot::QemuSnapshotHelper, //snapshot::QemuSnapshotHelper,
MmapPerms, MmapPerms,
@ -259,6 +260,7 @@ fn fuzz(
edges_map_mut_slice(), edges_map_mut_slice(),
addr_of_mut!(MAX_EDGES_NUM), addr_of_mut!(MAX_EDGES_NUM),
)) ))
.track_indices()
}; };
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
@ -267,7 +269,7 @@ fn fuzz(
// Create an observation channel using cmplog map // Create an observation channel using cmplog map
let cmplog_observer = CmpLogObserver::new("cmplog", true); let cmplog_observer = CmpLogObserver::new("cmplog", true);
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); let map_feedback = MaxMapFeedback::new(&edges_observer);
let calibration = CalibrationStage::new(&map_feedback); let calibration = CalibrationStage::new(&map_feedback);
@ -316,11 +318,10 @@ fn fuzz(
let power = StdPowerMutationalStage::new(mutator); let power = StdPowerMutationalStage::new(mutator);
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(PowerQueueScheduler::new( let scheduler = IndexesLenTimeMinimizerScheduler::new(
&mut state,
&edges_observer, &edges_observer,
PowerSchedule::FAST, PowerQueueScheduler::new(&mut state, &edges_observer, PowerSchedule::FAST),
)); );
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -34,7 +34,7 @@ use libafl::{
token_mutations::I2SRandReplace, token_mutations::I2SRandReplace,
tokens_mutations, StdMOptMutator, StdScheduledMutator, Tokens, tokens_mutations, StdMOptMutator, StdScheduledMutator, Tokens,
}, },
observers::{HitcountsMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver},
schedulers::{ schedulers::{
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
}, },
@ -310,14 +310,15 @@ fn fuzz_binary(
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
// We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges) // We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges)
let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }); let edges_observer =
HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }).track_indices();
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
let cmplog_observer = CmpLogObserver::new("cmplog", true); let cmplog_observer = CmpLogObserver::new("cmplog", true);
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); let map_feedback = MaxMapFeedback::new(&edges_observer);
let calibration = CalibrationStage::new(&map_feedback); let calibration = CalibrationStage::new(&map_feedback);
@ -374,11 +375,14 @@ fn fuzz_binary(
let power = StdPowerMutationalStage::new(mutator); let power = StdPowerMutationalStage::new(mutator);
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( let scheduler = IndexesLenTimeMinimizerScheduler::new(
&edges_observer,
StdWeightedScheduler::with_schedule(
&mut state, &mut state,
&edges_observer, &edges_observer,
Some(PowerSchedule::EXPLORE), Some(PowerSchedule::EXPLORE),
)); ),
);
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
@ -516,7 +520,9 @@ fn fuzz_text(
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
// We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges) // We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges)
let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }); let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") })
.track_indices()
.track_novelties();
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -524,7 +530,7 @@ fn fuzz_text(
let cmplog_observer = CmpLogObserver::new("cmplog", true); let cmplog_observer = CmpLogObserver::new("cmplog", true);
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, true); let map_feedback = MaxMapFeedback::new(&edges_observer);
let calibration = CalibrationStage::new(&map_feedback); let calibration = CalibrationStage::new(&map_feedback);
@ -594,11 +600,14 @@ fn fuzz_text(
let grimoire = StdMutationalStage::transforming(grimoire_mutator); let grimoire = StdMutationalStage::transforming(grimoire_mutator);
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( let scheduler = IndexesLenTimeMinimizerScheduler::new(
&edges_observer,
StdWeightedScheduler::with_schedule(
&mut state, &mut state,
&edges_observer, &edges_observer,
Some(PowerSchedule::EXPLORE), Some(PowerSchedule::EXPLORE),
)); ),
);
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -25,7 +25,7 @@ use libafl::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
token_mutations::{I2SRandReplace, Tokens}, token_mutations::{I2SRandReplace, Tokens},
}, },
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::{StdMutationalStage, TracingStage}, stages::{StdMutationalStage, TracingStage},
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
@ -136,7 +136,8 @@ pub extern "C" fn LLVMFuzzerRunDriver(
let edges_observer = HitcountsMapObserver::new(StdMapObserver::from_mut_slice( let edges_observer = HitcountsMapObserver::new(StdMapObserver::from_mut_slice(
"edges", "edges",
edges.into_iter().next().unwrap(), edges.into_iter().next().unwrap(),
)); ))
.track_indices();
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -148,7 +149,7 @@ pub extern "C" fn LLVMFuzzerRunDriver(
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, false), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -183,7 +184,8 @@ pub extern "C" fn LLVMFuzzerRunDriver(
} }
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler =
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -1,9 +1,5 @@
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts //! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
//! The example harness is built for libpng. //! The example harness is built for libpng.
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
use core::time::Duration; use core::time::Duration;
#[cfg(feature = "crash")] #[cfg(feature = "crash")]
use std::ptr; use std::ptr;
@ -22,7 +18,7 @@ use libafl::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
token_mutations::Tokens, token_mutations::Tokens,
}, },
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{ schedulers::{
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
}, },
@ -37,6 +33,10 @@ use libafl_bolts::{
AsSlice, AsSlice,
}; };
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM}; use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM};
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
/// The main fn, `no_mangle` as it is a C main /// The main fn, `no_mangle` as it is a C main
#[cfg(not(test))] #[cfg(not(test))]
@ -85,12 +85,13 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
EDGES_MAP.as_mut_ptr(), EDGES_MAP.as_mut_ptr(),
MAX_EDGES_NUM, MAX_EDGES_NUM,
)) ))
.track_indices()
}; };
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); let map_feedback = MaxMapFeedback::new(&edges_observer);
let calibration = CalibrationStage::new(&map_feedback); let calibration = CalibrationStage::new(&map_feedback);
@ -147,11 +148,10 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
let mut stages = tuple_list!(calibration, power); let mut stages = tuple_list!(calibration, power);
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( let scheduler = IndexesLenTimeMinimizerScheduler::new(
&mut state,
&edges_observer, &edges_observer,
Some(PowerSchedule::FAST), StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)),
)); );
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -2,10 +2,6 @@
//! The example harness is built for libpng. //! The example harness is built for libpng.
//! In this example, you will see the use of the `launcher` feature. //! In this example, you will see the use of the `launcher` feature.
//! The `launcher` will spawn new processes for each cpu core. //! The `launcher` will spawn new processes for each cpu core.
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
use core::time::Duration; use core::time::Duration;
use std::{env, net::SocketAddr, path::PathBuf}; use std::{env, net::SocketAddr, path::PathBuf};
@ -23,7 +19,7 @@ use libafl::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
token_mutations::Tokens, token_mutations::Tokens,
}, },
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{CoverageAccountingScheduler, QueueScheduler}, schedulers::{CoverageAccountingScheduler, QueueScheduler},
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
@ -40,6 +36,10 @@ use libafl_bolts::{
use libafl_targets::{ use libafl_targets::{
libfuzzer_initialize, libfuzzer_test_one_input, ACCOUNTING_MEMOP_MAP, EDGES_MAP, MAX_EDGES_NUM, libfuzzer_initialize, libfuzzer_test_one_input, ACCOUNTING_MEMOP_MAP, EDGES_MAP, MAX_EDGES_NUM,
}; };
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
/// Parse a millis string to a [`Duration`]. Used for arg parsing. /// Parse a millis string to a [`Duration`]. Used for arg parsing.
fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> { fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> {
@ -140,7 +140,8 @@ pub extern "C" fn libafl_main() {
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
let edges_observer = HitcountsMapObserver::new(unsafe { let edges_observer = HitcountsMapObserver::new(unsafe {
StdMapObserver::from_mut_ptr("edges", EDGES_MAP.as_mut_ptr(), MAX_EDGES_NUM) StdMapObserver::from_mut_ptr("edges", EDGES_MAP.as_mut_ptr(), MAX_EDGES_NUM)
}); })
.track_indices();
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -149,7 +150,7 @@ pub extern "C" fn libafl_main() {
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, false), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -194,10 +195,12 @@ pub extern "C" fn libafl_main() {
let mut stages = tuple_list!(StdMutationalStage::new(mutator)); let mut stages = tuple_list!(StdMutationalStage::new(mutator));
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = let scheduler = CoverageAccountingScheduler::new(
CoverageAccountingScheduler::new(&mut state, QueueScheduler::new(), unsafe { &edges_observer,
&ACCOUNTING_MEMOP_MAP &mut state,
}); QueueScheduler::new(),
unsafe { &ACCOUNTING_MEMOP_MAP },
);
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -1,9 +1,5 @@
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts //! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
//! The example harness is built for libpng. //! The example harness is built for libpng.
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
use core::time::Duration; use core::time::Duration;
#[cfg(feature = "crash")] #[cfg(feature = "crash")]
use std::ptr; use std::ptr;
@ -22,7 +18,7 @@ use libafl::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
token_mutations::Tokens, token_mutations::Tokens,
}, },
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{ schedulers::{
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
}, },
@ -37,6 +33,10 @@ use libafl_bolts::{
AsSlice, AsSlice,
}; };
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM}; use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM};
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
/// The main fn, `no_mangle` as it is a C main /// The main fn, `no_mangle` as it is a C main
#[cfg(not(test))] #[cfg(not(test))]
@ -99,12 +99,13 @@ fn fuzz(
EDGES_MAP.as_mut_ptr(), EDGES_MAP.as_mut_ptr(),
MAX_EDGES_NUM, MAX_EDGES_NUM,
)) ))
.track_indices()
}; };
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); let map_feedback = MaxMapFeedback::new(&edges_observer);
let calibration = CalibrationStage::new(&map_feedback); let calibration = CalibrationStage::new(&map_feedback);
@ -163,11 +164,10 @@ fn fuzz(
let mut stages = tuple_list!(calibration, power, aflstats); let mut stages = tuple_list!(calibration, power, aflstats);
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( let scheduler = IndexesLenTimeMinimizerScheduler::new(
&mut state,
&edges_observer, &edges_observer,
Some(PowerSchedule::FAST), StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)),
)); );
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -2,10 +2,6 @@
//! The example harness is built for libpng. //! The example harness is built for libpng.
//! In this example, you will see the use of the `launcher` feature. //! In this example, you will see the use of the `launcher` feature.
//! The `launcher` will spawn new processes for each cpu core. //! The `launcher` will spawn new processes for each cpu core.
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
use core::time::Duration; use core::time::Duration;
use std::{env, net::SocketAddr, path::PathBuf}; use std::{env, net::SocketAddr, path::PathBuf};
@ -23,7 +19,7 @@ use libafl::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
token_mutations::Tokens, token_mutations::Tokens,
}, },
observers::{HitcountsMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
@ -38,6 +34,10 @@ use libafl_bolts::{
AsSlice, AsSlice,
}; };
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer}; use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer};
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
/// Parse a millis string to a [`Duration`]. Used for arg parsing. /// Parse a millis string to a [`Duration`]. Used for arg parsing.
fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> { fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> {
@ -138,7 +138,8 @@ pub extern "C" fn libafl_main() {
let mut run_client = |state: Option<_>, mut mgr, _core_id: CoreId| { let mut run_client = |state: Option<_>, mut mgr, _core_id: CoreId| {
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }); let edges_observer =
HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }).track_indices();
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -147,7 +148,7 @@ pub extern "C" fn libafl_main() {
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, false), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -192,7 +193,8 @@ pub extern "C" fn libafl_main() {
let mut stages = tuple_list!(StdMutationalStage::new(mutator)); let mut stages = tuple_list!(StdMutationalStage::new(mutator));
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler =
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -1,9 +1,5 @@
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts //! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
//! The example harness is built for libpng. //! The example harness is built for libpng.
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
use core::time::Duration; use core::time::Duration;
#[cfg(feature = "crash")] #[cfg(feature = "crash")]
use std::ptr; use std::ptr;
@ -25,7 +21,7 @@ use libafl::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
token_mutations::Tokens, token_mutations::Tokens,
}, },
observers::{HitcountsMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver},
schedulers::{ schedulers::{
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
}, },
@ -40,6 +36,10 @@ use libafl_bolts::{
AsSlice, AsSlice,
}; };
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer}; use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer};
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
/// The main fn, `no_mangle` as it is a C main /// The main fn, `no_mangle` as it is a C main
#[cfg(not(test))] #[cfg(not(test))]
@ -82,14 +82,15 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
}; };
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }); let edges_observer =
HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }).track_indices();
let minimizer = StdCorpusMinimizer::new(&edges_observer); let minimizer = StdCorpusMinimizer::new(&edges_observer);
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); let map_feedback = MaxMapFeedback::new(&edges_observer);
let calibration = CalibrationStage::new(&map_feedback); let calibration = CalibrationStage::new(&map_feedback);
@ -146,11 +147,10 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
let mut stages = tuple_list!(calibration, power); let mut stages = tuple_list!(calibration, power);
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( let scheduler = IndexesLenTimeMinimizerScheduler::new(
&mut state,
&edges_observer, &edges_observer,
Some(PowerSchedule::FAST), StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)),
)); );
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -2,10 +2,6 @@
//! The example harness is built for libpng. //! The example harness is built for libpng.
//! In this example, you will see the use of the `launcher` feature. //! In this example, you will see the use of the `launcher` feature.
//! The `launcher` will spawn new processes for each cpu core. //! The `launcher` will spawn new processes for each cpu core.
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
use core::time::Duration; use core::time::Duration;
use std::{env, net::SocketAddr, path::PathBuf}; use std::{env, net::SocketAddr, path::PathBuf};
@ -23,7 +19,7 @@ use libafl::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
token_mutations::Tokens, token_mutations::Tokens,
}, },
observers::{HitcountsMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
@ -38,6 +34,10 @@ use libafl_bolts::{
AsSlice, AsSlice,
}; };
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer}; use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer};
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
/// Parse a millis string to a [`Duration`]. Used for arg parsing. /// Parse a millis string to a [`Duration`]. Used for arg parsing.
fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> { fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> {
@ -139,7 +139,8 @@ pub extern "C" fn libafl_main() {
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 // Create an observation channel using the coverage map
let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }); let edges_observer =
HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }).track_indices();
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -148,7 +149,7 @@ pub extern "C" fn libafl_main() {
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, false), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -193,7 +194,8 @@ pub extern "C" fn libafl_main() {
let mut stages = tuple_list!(StdMutationalStage::new(mutator)); let mut stages = tuple_list!(StdMutationalStage::new(mutator));
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler =
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -2,9 +2,6 @@
//! The example harness is built for libpng. //! The example harness is built for libpng.
//! In this example, you will see the use of the `launcher` feature. //! In this example, you will see the use of the `launcher` feature.
//! The `launcher` will spawn new processes for each cpu core. //! The `launcher` will spawn new processes for each cpu core.
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
use core::time::Duration; use core::time::Duration;
use std::{env, net::SocketAddr, path::PathBuf}; use std::{env, net::SocketAddr, path::PathBuf};
@ -26,7 +23,7 @@ use libafl::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
token_mutations::Tokens, token_mutations::Tokens,
}, },
observers::{HitcountsMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
@ -41,6 +38,10 @@ use libafl_bolts::{
AsSlice, AsSlice,
}; };
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer}; use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer};
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
/// Parse a millis string to a [`Duration`]. Used for arg parsing. /// Parse a millis string to a [`Duration`]. Used for arg parsing.
fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> { fn timeout_from_millis_str(time: &str) -> Result<Duration, Error> {
@ -163,7 +164,8 @@ pub extern "C" fn libafl_main() {
mut restarting_mgr: LlmpRestartingEventManager<_, _, _>, mut restarting_mgr: LlmpRestartingEventManager<_, _, _>,
core_id| { core_id| {
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }); let edges_observer =
HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }).track_indices();
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -172,7 +174,7 @@ pub extern "C" fn libafl_main() {
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, false), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -217,7 +219,8 @@ pub extern "C" fn libafl_main() {
let mut stages = tuple_list!(StdMutationalStage::new(mutator)); let mut stages = tuple_list!(StdMutationalStage::new(mutator));
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler =
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -1,9 +1,5 @@
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts //! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
//! The example harness is built for libpng. //! The example harness is built for libpng.
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
use core::time::Duration; use core::time::Duration;
#[cfg(feature = "crash")] #[cfg(feature = "crash")]
use std::ptr; use std::ptr;
@ -22,7 +18,7 @@ use libafl::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
token_mutations::Tokens, token_mutations::Tokens,
}, },
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{ schedulers::{
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
}, },
@ -37,6 +33,10 @@ use libafl_bolts::{
AsSlice, AsSlice,
}; };
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM}; use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, EDGES_MAP, MAX_EDGES_NUM};
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
/// The main fn, `no_mangle` as it is a C main /// The main fn, `no_mangle` as it is a C main
#[no_mangle] #[no_mangle]
@ -83,12 +83,13 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
EDGES_MAP.as_mut_ptr(), EDGES_MAP.as_mut_ptr(),
MAX_EDGES_NUM, MAX_EDGES_NUM,
)) ))
.track_indices()
}; };
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); let map_feedback = MaxMapFeedback::new(&edges_observer);
let calibration = CalibrationStage::new(&map_feedback); let calibration = CalibrationStage::new(&map_feedback);
@ -145,11 +146,10 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
let mut stages = tuple_list!(calibration, power); let mut stages = tuple_list!(calibration, power);
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( let scheduler = IndexesLenTimeMinimizerScheduler::new(
&mut state,
&edges_observer, &edges_observer,
Some(PowerSchedule::FAST), StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)),
)); );
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -19,7 +19,7 @@ use libafl::{
scheduled::{havoc_mutations, StdScheduledMutator}, scheduled::{havoc_mutations, StdScheduledMutator},
token_mutations::I2SRandReplace, token_mutations::I2SRandReplace,
}, },
observers::TimeObserver, observers::{CanTrack, TimeObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::{ShadowTracingStage, StdMutationalStage}, stages::{ShadowTracingStage, StdMutationalStage},
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
@ -68,7 +68,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
// We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges) // We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges)
let edges_observer = unsafe { std_edges_map_observer("edges") }; let edges_observer = unsafe { std_edges_map_observer("edges").track_indices() };
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -79,7 +79,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, false), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -109,7 +109,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
println!("We're a client, let's fuzz :)"); println!("We're a client, let's fuzz :)");
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -1,11 +1,7 @@
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts //! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
//! The example harness is built for `stb_image`. //! The example harness is built for `stb_image`.
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
use std::{ use std::{
env, env, fs,
path::PathBuf, path::PathBuf,
process::{Child, Command, Stdio}, process::{Child, Command, Stdio},
time::Duration, time::Duration,
@ -32,7 +28,7 @@ use libafl::{
serialization_format::{DEFAULT_ENV_NAME, DEFAULT_SIZE}, serialization_format::{DEFAULT_ENV_NAME, DEFAULT_SIZE},
ConcolicObserver, ConcolicObserver,
}, },
TimeObserver, TimeObserver, CanTrack,
}, },
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::{ stages::{
@ -52,6 +48,10 @@ use libafl_bolts::{
use libafl_targets::{ use libafl_targets::{
libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer, CmpLogObserver, libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer, CmpLogObserver,
}; };
use mimalloc::MiMalloc;
#[global_allocator]
static GLOBAL: MiMalloc = MiMalloc;
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
struct Opt { struct Opt {
@ -60,7 +60,6 @@ struct Opt {
concolic: bool, concolic: bool,
} }
use std::fs;
pub fn main() { pub fn main() {
// Registry the metadata types used in this fuzzer // Registry the metadata types used in this fuzzer
// Needed only on no_std // Needed only on no_std
@ -107,7 +106,7 @@ fn fuzz(
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
// We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges) // We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges)
let edges_observer = unsafe { std_edges_map_observer("edges") }; let edges_observer = unsafe { std_edges_map_observer("edges").track_indices() };
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -118,7 +117,7 @@ fn fuzz(
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, false), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -148,7 +147,7 @@ fn fuzz(
println!("We're a client, let's fuzz :)"); println!("We're a client, let's fuzz :)");
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -11,7 +11,7 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
observers::{HitcountsMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver},
schedulers::{ schedulers::{
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
}, },
@ -61,12 +61,13 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
}; };
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
let edges_observer = unsafe { HitcountsMapObserver::new(std_edges_map_observer("edges")) }; let edges_observer =
unsafe { HitcountsMapObserver::new(std_edges_map_observer("edges")).track_indices() };
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); let map_feedback = MaxMapFeedback::new(&edges_observer);
let calibration = CalibrationStage::new(&map_feedback); let calibration = CalibrationStage::new(&map_feedback);
@ -112,11 +113,10 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
let mut stages = tuple_list!(calibration, power); let mut stages = tuple_list!(calibration, power);
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(StdWeightedScheduler::with_schedule( let scheduler = IndexesLenTimeMinimizerScheduler::new(
&mut state,
&edges_observer, &edges_observer,
Some(PowerSchedule::FAST), StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)),
)); );
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -30,6 +30,7 @@ use libafl_bolts::{
use libafl_qemu::{ use libafl_qemu::{
edges::{QemuEdgeCoverageChildHelper, EDGES_MAP_PTR, EDGES_MAP_SIZE}, edges::{QemuEdgeCoverageChildHelper, EDGES_MAP_PTR, EDGES_MAP_SIZE},
elf::EasyElf, elf::EasyElf,
emu::Emulator,
ArchExtras, CallingConvention, GuestAddr, GuestReg, MmapPerms, Qemu, QemuExitReason, ArchExtras, CallingConvention, GuestAddr, GuestReg, MmapPerms, Qemu, QemuExitReason,
QemuExitReasonError, QemuForkExecutor, QemuHooks, QemuShutdownCause, Regs, QemuExitReasonError, QemuForkExecutor, QemuHooks, QemuShutdownCause, Regs,
}; };
@ -171,7 +172,7 @@ pub fn fuzz() -> Result<(), Error> {
)) ))
}; };
let mut feedback = MaxMapFeedback::tracking(&edges_observer, true, false); let mut feedback = MaxMapFeedback::new(&edges_observer);
#[allow(clippy::let_unit_value)] #[allow(clippy::let_unit_value)]
let mut objective = (); let mut objective = ();

View File

@ -18,7 +18,7 @@ use libafl::{
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations,
StdMOptMutator, StdScheduledMutator, Tokens, StdMOptMutator, StdScheduledMutator, Tokens,
}, },
observers::{HitcountsMapObserver, TimeObserver, VariableMapObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver},
schedulers::{ schedulers::{
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, PowerQueueScheduler, powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, PowerQueueScheduler,
}, },
@ -81,12 +81,13 @@ impl<'a, M: Monitor> Instance<'a, M> {
edges_map_mut_slice(), edges_map_mut_slice(),
addr_of_mut!(MAX_EDGES_NUM), addr_of_mut!(MAX_EDGES_NUM),
)) ))
.track_indices()
}; };
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); let map_feedback = MaxMapFeedback::new(&edges_observer);
let calibration = CalibrationStage::new(&map_feedback); let calibration = CalibrationStage::new(&map_feedback);
@ -124,11 +125,10 @@ impl<'a, M: Monitor> Instance<'a, M> {
}; };
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(PowerQueueScheduler::new( let scheduler = IndexesLenTimeMinimizerScheduler::new(
&mut state,
&edges_observer, &edges_observer,
PowerSchedule::FAST, PowerQueueScheduler::new(&mut state, &edges_observer, PowerSchedule::FAST),
)); );
let observers = tuple_list!(edges_observer, time_observer); let observers = tuple_list!(edges_observer, time_observer);

View File

@ -13,7 +13,7 @@ use libafl::{
inputs::BytesInput, inputs::BytesInput,
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::scheduled::{havoc_mutations, StdScheduledMutator},
observers::{HitcountsMapObserver, TimeObserver, VariableMapObserver}, observers::{HitcountsMapObserver, TimeObserver, TrackingHinted, VariableMapObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::{CalibrationStage, StdMutationalStage}, stages::{CalibrationStage, StdMutationalStage},
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
@ -157,6 +157,7 @@ pub fn fuzz() {
edges_map_mut_slice(), edges_map_mut_slice(),
addr_of_mut!(MAX_EDGES_NUM), addr_of_mut!(MAX_EDGES_NUM),
)) ))
.track_indices()
}; };
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
@ -166,7 +167,7 @@ pub fn fuzz() {
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, true), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -194,7 +195,8 @@ pub fn fuzz() {
}); });
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler =
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
@ -206,7 +208,7 @@ pub fn fuzz() {
// Setup an havoc mutator with a mutational stage // Setup an havoc mutator with a mutational stage
let mutator = StdScheduledMutator::new(havoc_mutations()); let mutator = StdScheduledMutator::new(havoc_mutations());
let calibration_feedback = MaxMapFeedback::tracking(&edges_observer, true, true); let calibration_feedback = MaxMapFeedback::new(&edges_observer);
let mut stages = tuple_list!( let mut stages = tuple_list!(
StdMutationalStage::new(mutator), StdMutationalStage::new(mutator),
CalibrationStage::new(&calibration_feedback) CalibrationStage::new(&calibration_feedback)

View File

@ -13,7 +13,7 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::scheduled::{havoc_mutations, StdScheduledMutator},
observers::{HitcountsMapObserver, TimeObserver, VariableMapObserver}, observers::{HitcountsMapObserver, TimeObserver, TrackingHinted, VariableMapObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::StdMutationalStage, stages::StdMutationalStage,
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
@ -164,6 +164,7 @@ pub fn fuzz() {
edges_map_mut_slice(), edges_map_mut_slice(),
addr_of_mut!(MAX_EDGES_NUM), addr_of_mut!(MAX_EDGES_NUM),
)) ))
.track_indices()
}; };
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
@ -173,7 +174,7 @@ pub fn fuzz() {
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, true), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -201,7 +202,8 @@ pub fn fuzz() {
}); });
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler =
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -13,7 +13,7 @@ use libafl::{
inputs::BytesInput, inputs::BytesInput,
monitors::MultiMonitor, monitors::MultiMonitor,
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::scheduled::{havoc_mutations, StdScheduledMutator},
observers::{HitcountsMapObserver, TimeObserver, VariableMapObserver}, observers::{HitcountsMapObserver, TimeObserver, TrackingHinted, VariableMapObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::{CalibrationStage, StdMutationalStage}, stages::{CalibrationStage, StdMutationalStage},
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
@ -98,6 +98,7 @@ pub fn fuzz() {
edges_map_mut_slice(), edges_map_mut_slice(),
addr_of_mut!(MAX_EDGES_NUM), addr_of_mut!(MAX_EDGES_NUM),
)) ))
.track_indices()
}; };
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
@ -107,7 +108,7 @@ pub fn fuzz() {
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, true), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -135,7 +136,8 @@ pub fn fuzz() {
}); });
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler =
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
@ -147,7 +149,7 @@ pub fn fuzz() {
// Setup an havoc mutator with a mutational stage // Setup an havoc mutator with a mutational stage
let mutator = StdScheduledMutator::new(havoc_mutations()); let mutator = StdScheduledMutator::new(havoc_mutations());
let calibration_feedback = MaxMapFeedback::tracking(&edges_observer, true, true); let calibration_feedback = MaxMapFeedback::new(&edges_observer);
let mut stages = tuple_list!( let mut stages = tuple_list!(
StdMutationalStage::new(mutator), StdMutationalStage::new(mutator),
CalibrationStage::new(&calibration_feedback) CalibrationStage::new(&calibration_feedback)

View File

@ -15,7 +15,7 @@ use libafl::{
fuzzer::StdFuzzer, fuzzer::StdFuzzer,
inputs::HasTargetBytes, inputs::HasTargetBytes,
monitors::MultiMonitor, monitors::MultiMonitor,
observers::{HitcountsMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver},
schedulers::{powersched::PowerSchedule, PowerQueueScheduler}, schedulers::{powersched::PowerSchedule, PowerQueueScheduler},
stages::{calibrate::CalibrationStage, power::StdPowerMutationalStage}, stages::{calibrate::CalibrationStage, power::StdPowerMutationalStage},
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
@ -81,12 +81,13 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
}; };
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }); let edges_observer =
HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }).track_indices();
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, false); let map_feedback = MaxMapFeedback::new(&edges_observer);
let calibration = CalibrationStage::new(&map_feedback); let calibration = CalibrationStage::new(&map_feedback);
@ -132,11 +133,10 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
let mut stages = tuple_list!(calibration, power); let mut stages = tuple_list!(calibration, power);
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = PacketLenMinimizerScheduler::new(PowerQueueScheduler::new( let scheduler = PacketLenMinimizerScheduler::new(
&mut state,
&edges_observer, &edges_observer,
PowerSchedule::FAST, PowerQueueScheduler::new(&mut state, &edges_observer, PowerSchedule::FAST),
)); );
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -32,8 +32,8 @@ where
} }
} }
pub type PacketLenMinimizerScheduler<CS> = pub type PacketLenMinimizerScheduler<CS, O> =
MinimizerScheduler<CS, PacketLenTestcaseScore, MapIndexesMetadata>; MinimizerScheduler<CS, PacketLenTestcaseScore, MapIndexesMetadata, O>;
#[derive(Serialize, Deserialize, Default, Clone, Debug)] #[derive(Serialize, Deserialize, Default, Clone, Debug)]
pub struct PacketLenFeedback { pub struct PacketLenFeedback {

View File

@ -186,6 +186,9 @@ bitvec = { version = "1.0", optional = true, features = ["serde"] } # used for s
arrayvec = { version = "0.7.4", optional = true, default-features = false } # used for fixed-len collects arrayvec = { version = "0.7.4", optional = true, default-features = false } # used for fixed-len collects
const_format = "0.2.32" # used for providing helpful compiler output
const_panic = "0.2.8" # similarly, for formatting const panic output
# optional-dev deps (change when target.'cfg(accessible(::std))'.test-dependencies will be stable) # optional-dev deps (change when target.'cfg(accessible(::std))'.test-dependencies will be stable)
serial_test = { version = "2", optional = true, default-features = false, features = ["logging"] } serial_test = { version = "2", optional = true, default-features = false, features = ["logging"] }

View File

@ -49,32 +49,25 @@ where
/// ///
/// Algorithm based on WMOPT: <https://hexhive.epfl.ch/publications/files/21ISSTA2.pdf> /// Algorithm based on WMOPT: <https://hexhive.epfl.ch/publications/files/21ISSTA2.pdf>
#[derive(Debug)] #[derive(Debug)]
pub struct MapCorpusMinimizer<E, O, T, TS> pub struct MapCorpusMinimizer<C, E, O, T, TS> {
where
E: UsesState,
E::State: HasCorpus + HasMetadata,
TS: TestcaseScore<E::State>,
{
obs_name: String, obs_name: String,
phantom: PhantomData<(E, O, T, TS)>, phantom: PhantomData<(C, E, O, T, TS)>,
} }
/// Standard corpus minimizer, which weights inputs by length and time. /// Standard corpus minimizer, which weights inputs by length and time.
pub type StdCorpusMinimizer<E, O, T> = pub type StdCorpusMinimizer<C, E, O, T> =
MapCorpusMinimizer<E, O, T, LenTimeMulTestcaseScore<<E as UsesState>::State>>; MapCorpusMinimizer<C, E, O, T, LenTimeMulTestcaseScore<<E as UsesState>::State>>;
impl<E, O, T, TS> MapCorpusMinimizer<E, O, T, TS> impl<C, E, O, T, TS> MapCorpusMinimizer<C, E, O, T, TS>
where where
E: UsesState, E: UsesState,
E::State: HasCorpus + HasMetadata, E::State: HasCorpus + HasMetadata,
TS: TestcaseScore<E::State>, TS: TestcaseScore<E::State>,
C: Named,
{ {
/// Constructs a new `MapCorpusMinimizer` from a provided observer. This observer will be used /// Constructs a new `MapCorpusMinimizer` from a provided observer. This observer will be used
/// in the future to get observed maps from an executed input. /// in the future to get observed maps from an executed input.
pub fn new(obs: &O) -> Self pub fn new(obs: &C) -> Self {
where
O: Named,
{
Self { Self {
obs_name: obs.name().to_string(), obs_name: obs.name().to_string(),
phantom: PhantomData, phantom: PhantomData,
@ -82,10 +75,11 @@ where
} }
} }
impl<E, O, T, TS> CorpusMinimizer<E> for MapCorpusMinimizer<E, O, T, TS> impl<C, E, O, T, TS> CorpusMinimizer<E> for MapCorpusMinimizer<C, E, O, T, TS>
where where
E: UsesState, E: UsesState,
for<'a> O: MapObserver<Entry = T> + AsIter<'a, Item = T>, for<'a> O: MapObserver<Entry = T> + AsIter<'a, Item = T>,
C: AsRef<O>,
E::State: HasMetadata + HasCorpus + HasExecutions, E::State: HasMetadata + HasCorpus + HasExecutions,
T: Copy + Hash + Eq, T: Copy + Hash + Eq,
TS: TestcaseScore<E::State>, TS: TestcaseScore<E::State>,
@ -165,10 +159,11 @@ where
)?; )?;
let seed_expr = Bool::fresh_const(&ctx, "seed"); let seed_expr = Bool::fresh_const(&ctx, "seed");
let obs: &O = executor let obs = executor
.observers() .observers()
.match_name::<O>(&self.obs_name) .match_name::<C>(&self.obs_name)
.expect("Observer must be present."); .expect("Observer must be present.")
.as_ref();
// Store coverage, mapping coverage map indices to hit counts (if present) and the // Store coverage, mapping coverage map indices to hit counts (if present) and the
// associated seeds for the map indices with those hit counts. // associated seeds for the map indices with those hit counts.

View File

@ -1499,7 +1499,7 @@ where
} }
/// A manager-like llmp client that converts between input types /// A manager-like llmp client that converts between input types
pub struct LlmpEventConverter<IC, ICB, DI, S, SP> pub struct LlmpEventConverter<DI, IC, ICB, S, SP>
where where
S: UsesInput, S: UsesInput,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
@ -1517,7 +1517,7 @@ where
phantom: PhantomData<S>, phantom: PhantomData<S>,
} }
impl<IC, ICB, DI, S, SP> core::fmt::Debug for LlmpEventConverter<IC, ICB, DI, S, SP> impl<DI, IC, ICB, S, SP> core::fmt::Debug for LlmpEventConverter<DI, IC, ICB, S, SP>
where where
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
S: UsesInput, S: UsesInput,
@ -1539,7 +1539,7 @@ where
} }
} }
impl<IC, ICB, DI, S, SP> LlmpEventConverter<IC, ICB, DI, S, SP> impl<DI, IC, ICB, S, SP> LlmpEventConverter<DI, IC, ICB, S, SP>
where where
S: UsesInput + HasExecutions + HasMetadata, S: UsesInput + HasExecutions + HasMetadata,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
@ -1734,7 +1734,7 @@ where
} }
} }
impl<IC, ICB, DI, S, SP> UsesState for LlmpEventConverter<IC, ICB, DI, S, SP> impl<DI, IC, ICB, S, SP> UsesState for LlmpEventConverter<DI, IC, ICB, S, SP>
where where
S: State, S: State,
SP: ShMemProvider, SP: ShMemProvider,
@ -1745,7 +1745,7 @@ where
type State = S; type State = S;
} }
impl<IC, ICB, DI, S, SP> EventFirer for LlmpEventConverter<IC, ICB, DI, S, SP> impl<DI, IC, ICB, S, SP> EventFirer for LlmpEventConverter<DI, IC, ICB, S, SP>
where where
S: State, S: State,
SP: ShMemProvider, SP: ShMemProvider,

View File

@ -636,13 +636,14 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
/// Builds `ForkserverExecutor` downsizing the coverage map to fit exaclty the AFL++ map size. /// Builds `ForkserverExecutor` downsizing the coverage map to fit exaclty the AFL++ map size.
#[allow(clippy::pedantic)] #[allow(clippy::pedantic)]
pub fn build_dynamic_map<MO, OT, S>( pub fn build_dynamic_map<A, MO, OT, S>(
&mut self, &mut self,
mut map_observer: MO, mut map_observer: A,
other_observers: OT, other_observers: OT,
) -> Result<ForkserverExecutor<(MO, OT), S, SP>, Error> ) -> Result<ForkserverExecutor<(A, OT), S, SP>, Error>
where where
MO: Observer<S> + MapObserver + Truncate, // TODO maybe enforce Entry = u8 for the cov map MO: MapObserver + Truncate, // TODO maybe enforce Entry = u8 for the cov map
A: Observer<S> + AsRef<MO> + AsMut<MO>,
OT: ObserversTuple<S> + Prepend<MO, PreprendResult = OT>, OT: ObserversTuple<S> + Prepend<MO, PreprendResult = OT>,
S: UsesInput, S: UsesInput,
S::Input: Input + HasTargetBytes, S::Input: Input + HasTargetBytes,
@ -660,10 +661,10 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
); );
if let Some(dynamic_map_size) = self.map_size { if let Some(dynamic_map_size) = self.map_size {
map_observer.truncate(dynamic_map_size); map_observer.as_mut().truncate(dynamic_map_size);
} }
let observers: (MO, OT) = other_observers.prepend(map_observer); let observers = (map_observer, other_observers);
if self.uses_shmem_testcase && map.is_none() { if self.uses_shmem_testcase && map.is_none() {
return Err(Error::illegal_state( return Err(Error::illegal_state(

View File

@ -23,28 +23,29 @@ use crate::{
feedbacks::{Feedback, HasObserverName}, feedbacks::{Feedback, HasObserverName},
inputs::UsesInput, inputs::UsesInput,
monitors::{AggregatorOps, UserStats, UserStatsValue}, monitors::{AggregatorOps, UserStats, UserStatsValue},
observers::{MapObserver, Observer, ObserversTuple, UsesObserver}, observers::{CanTrack, MapObserver, Observer, ObserversTuple, UsesObserver},
state::State, state::State,
Error, HasMetadata, HasNamedMetadata, Error, HasMetadata, HasNamedMetadata,
}; };
/// A [`MapFeedback`] that implements the AFL algorithm using an [`OrReducer`] combining the bits for the history map and the bit from ``HitcountsMapObserver``. /// A [`MapFeedback`] that implements the AFL algorithm using an [`OrReducer`] combining the bits for the history map and the bit from (`HitcountsMapObserver`)[`crate::observers::HitcountsMapObserver`].
pub type AflMapFeedback<O, S, T> = MapFeedback<DifferentIsNovel, O, OrReducer, S, T>; pub type AflMapFeedback<C, O, S, T> = MapFeedback<C, DifferentIsNovel, O, OrReducer, S, T>;
/// A [`MapFeedback`] that strives to maximize the map contents. /// A [`MapFeedback`] that strives to maximize the map contents.
pub type MaxMapFeedback<O, S, T> = MapFeedback<DifferentIsNovel, O, MaxReducer, S, T>; pub type MaxMapFeedback<C, O, S, T> = MapFeedback<C, DifferentIsNovel, O, MaxReducer, S, T>;
/// A [`MapFeedback`] that strives to minimize the map contents. /// A [`MapFeedback`] that strives to minimize the map contents.
pub type MinMapFeedback<O, S, T> = MapFeedback<DifferentIsNovel, O, MinReducer, S, T>; pub type MinMapFeedback<C, O, S, T> = MapFeedback<C, DifferentIsNovel, O, MinReducer, S, T>;
/// A [`MapFeedback`] that always returns `true` for `is_interesting`. Useful for tracing all executions. /// A [`MapFeedback`] that always returns `true` for `is_interesting`. Useful for tracing all executions.
pub type AlwaysInterestingMapFeedback<O, S, T> = MapFeedback<AllIsNovel, O, NopReducer, S, T>; pub type AlwaysInterestingMapFeedback<C, O, S, T> = MapFeedback<C, AllIsNovel, O, NopReducer, S, T>;
/// A [`MapFeedback`] that strives to maximize the map contents, /// A [`MapFeedback`] that strives to maximize the map contents,
/// but only, if a value is larger than `pow2` of the previous. /// but only, if a value is larger than `pow2` of the previous.
pub type MaxMapPow2Feedback<O, S, T> = MapFeedback<NextPow2IsNovel, O, MaxReducer, S, T>; pub type MaxMapPow2Feedback<C, O, S, T> = MapFeedback<C, NextPow2IsNovel, O, MaxReducer, S, T>;
/// A [`MapFeedback`] that strives to maximize the map contents, /// A [`MapFeedback`] that strives to maximize the map contents,
/// but only, if a value is larger than `pow2` of the previous. /// but only, if a value is larger than `pow2` of the previous.
pub type MaxMapOneOrFilledFeedback<O, S, T> = MapFeedback<OneOrFilledIsNovel, O, MaxReducer, S, T>; pub type MaxMapOneOrFilledFeedback<C, O, S, T> =
MapFeedback<C, OneOrFilledIsNovel, O, MaxReducer, S, T>;
/// A `Reducer` function is used to aggregate values for the novelty search /// A `Reducer` function is used to aggregate values for the novelty search
pub trait Reducer<T>: 'static pub trait Reducer<T>: 'static
@ -174,6 +175,7 @@ fn saturating_next_power_of_two<T: PrimInt>(n: T) -> T {
/// Consider as novelty if the reduced value is different from the old value. /// Consider as novelty if the reduced value is different from the old value.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct DifferentIsNovel {} pub struct DifferentIsNovel {}
impl<T> IsNovel<T> for DifferentIsNovel impl<T> IsNovel<T> for DifferentIsNovel
where where
T: PartialEq + Default + Copy + 'static, T: PartialEq + Default + Copy + 'static,
@ -187,6 +189,7 @@ where
/// Only consider as novel the values which are at least the next pow2 class of the old value /// Only consider as novel the values which are at least the next pow2 class of the old value
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct NextPow2IsNovel {} pub struct NextPow2IsNovel {}
impl<T> IsNovel<T> for NextPow2IsNovel impl<T> IsNovel<T> for NextPow2IsNovel
where where
T: PrimInt + Default + Copy + 'static, T: PrimInt + Default + Copy + 'static,
@ -207,6 +210,7 @@ where
/// Only consider `T::one()` or `T::max_value()`, if they are bigger than the old value, as novel /// Only consider `T::one()` or `T::max_value()`, if they are bigger than the old value, as novel
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct OneOrFilledIsNovel {} pub struct OneOrFilledIsNovel {}
impl<T> IsNovel<T> for OneOrFilledIsNovel impl<T> IsNovel<T> for OneOrFilledIsNovel
where where
T: PrimInt + Default + Copy + 'static, T: PrimInt + Default + Copy + 'static,
@ -239,6 +243,7 @@ impl AsSlice for MapIndexesMetadata {
self.list.as_slice() self.list.as_slice()
} }
} }
impl AsMutSlice for MapIndexesMetadata { impl AsMutSlice for MapIndexesMetadata {
type Entry = usize; type Entry = usize;
/// Convert to a slice /// Convert to a slice
@ -286,6 +291,7 @@ impl AsSlice for MapNoveltiesMetadata {
self.list.as_slice() self.list.as_slice()
} }
} }
impl AsMutSlice for MapNoveltiesMetadata { impl AsMutSlice for MapNoveltiesMetadata {
type Entry = usize; type Entry = usize;
/// Convert to a slice /// Convert to a slice
@ -294,6 +300,7 @@ impl AsMutSlice for MapNoveltiesMetadata {
self.list.as_mut_slice() self.list.as_mut_slice()
} }
} }
impl MapNoveltiesMetadata { impl MapNoveltiesMetadata {
/// Creates a new [`struct@MapNoveltiesMetadata`] /// Creates a new [`struct@MapNoveltiesMetadata`]
#[must_use] #[must_use]
@ -376,9 +383,7 @@ where
/// The most common AFL-like feedback type /// The most common AFL-like feedback type
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct MapFeedback<N, O, R, S, T> { pub struct MapFeedback<C, N, O, R, S, T> {
/// Indexes used in the last observation
indexes: bool,
/// New indexes observed in the last observation /// New indexes observed in the last observation
novelties: Option<Vec<usize>>, novelties: Option<Vec<usize>>,
/// Name identifier of this instance /// Name identifier of this instance
@ -388,24 +393,25 @@ pub struct MapFeedback<N, O, R, S, T> {
/// Name of the feedback as shown in the `UserStats` /// Name of the feedback as shown in the `UserStats`
stats_name: String, stats_name: String,
/// Phantom Data of Reducer /// Phantom Data of Reducer
phantom: PhantomData<(N, O, R, S, T)>, phantom: PhantomData<(C, N, O, R, S, T)>,
} }
impl<N, O, R, S, T> UsesObserver<S> for MapFeedback<N, O, R, S, T> impl<C, N, O, R, S, T> UsesObserver<S> for MapFeedback<C, N, O, R, S, T>
where where
S: UsesInput, S: UsesInput,
O: Observer<S>, C: AsRef<O> + Observer<S>,
{ {
type Observer = O; type Observer = C;
} }
impl<N, O, R, S, T> Feedback<S> for MapFeedback<N, O, R, S, T> impl<C, N, O, R, S, T> Feedback<S> for MapFeedback<C, N, O, R, S, T>
where where
N: IsNovel<T>, N: IsNovel<T>,
O: MapObserver<Entry = T> + for<'it> AsIter<'it, Item = T>, O: MapObserver<Entry = T> + for<'it> AsIter<'it, Item = T>,
R: Reducer<T>, R: Reducer<T>,
S: State + HasNamedMetadata, S: State + HasNamedMetadata,
T: Default + Copy + Serialize + for<'de> Deserialize<'de> + PartialEq + Debug + 'static, T: Default + Copy + Serialize + for<'de> Deserialize<'de> + PartialEq + Debug + 'static,
C: CanTrack + AsRef<O>,
{ {
fn init_state(&mut self, state: &mut S) -> Result<(), Error> { fn init_state(&mut self, state: &mut S) -> Result<(), Error> {
// Initialize `MapFeedbackMetadata` with an empty vector and add it to the state. // Initialize `MapFeedbackMetadata` with an empty vector and add it to the state.
@ -461,7 +467,10 @@ where
let meta = MapNoveltiesMetadata::new(novelties); let meta = MapNoveltiesMetadata::new(novelties);
testcase.add_metadata(meta); testcase.add_metadata(meta);
} }
let observer = observers.match_name::<O>(&self.observer_name).unwrap(); let observer = observers
.match_name::<C>(&self.observer_name)
.unwrap()
.as_ref();
let initial = observer.initial(); let initial = observer.initial();
let map_state = state let map_state = state
.named_metadata_map_mut() .named_metadata_map_mut()
@ -473,7 +482,7 @@ where
} }
let history_map = map_state.history_map.as_mut_slice(); let history_map = map_state.history_map.as_mut_slice();
if self.indexes { if C::INDICES {
let mut indices = Vec::new(); let mut indices = Vec::new();
for (i, value) in observer for (i, value) in observer
@ -540,11 +549,12 @@ where
/// Specialize for the common coverage map size, maximization of u8s /// Specialize for the common coverage map size, maximization of u8s
#[rustversion::nightly] #[rustversion::nightly]
impl<O, S> Feedback<S> for MapFeedback<DifferentIsNovel, O, MaxReducer, S, u8> impl<C, O, S> Feedback<S> for MapFeedback<C, DifferentIsNovel, O, MaxReducer, S, u8>
where where
O: MapObserver<Entry = u8> + AsSlice<Entry = u8>, O: MapObserver<Entry = u8> + AsSlice<Entry = u8>,
for<'it> O: AsIter<'it, Item = u8>, for<'it> O: AsIter<'it, Item = u8>,
S: State + HasNamedMetadata, S: State + HasNamedMetadata,
C: CanTrack + AsRef<O>,
{ {
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
#[allow(clippy::needless_range_loop)] #[allow(clippy::needless_range_loop)]
@ -565,7 +575,10 @@ where
let mut interesting = false; let mut interesting = false;
// TODO Replace with match_name_type when stable // TODO Replace with match_name_type when stable
let observer = observers.match_name::<O>(&self.observer_name).unwrap(); let observer = observers
.match_name::<C>(&self.observer_name)
.unwrap()
.as_ref();
let map_state = state let map_state = state
.named_metadata_map_mut() .named_metadata_map_mut()
@ -656,21 +669,17 @@ where
} }
} }
impl<N, O, R, S, T> Named for MapFeedback<N, O, R, S, T> { impl<C, N, O, R, S, T> Named for MapFeedback<C, N, O, R, S, T> {
#[inline] #[inline]
fn name(&self) -> &str { fn name(&self) -> &str {
self.name.as_str() self.name.as_str()
} }
} }
impl<N, O, R, S, T> HasObserverName for MapFeedback<N, O, R, S, T> impl<C, N, O, R, S, T> HasObserverName for MapFeedback<C, N, O, R, S, T>
where where
T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug, O: Named,
R: Reducer<T>, C: AsRef<O>,
N: IsNovel<T>,
O: MapObserver<Entry = T>,
for<'it> O: AsIter<'it, Item = T>,
S: HasNamedMetadata,
{ {
#[inline] #[inline]
fn observer_name(&self) -> &str { fn observer_name(&self) -> &str {
@ -682,7 +691,7 @@ fn create_stats_name(name: &str) -> String {
name.to_lowercase() name.to_lowercase()
} }
impl<N, O, R, S, T> MapFeedback<N, O, R, S, T> impl<C, N, O, R, S, T> MapFeedback<C, N, O, R, S, T>
where where
T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug, T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug,
R: Reducer<T>, R: Reducer<T>,
@ -690,13 +699,14 @@ where
for<'it> O: AsIter<'it, Item = T>, for<'it> O: AsIter<'it, Item = T>,
N: IsNovel<T>, N: IsNovel<T>,
S: UsesInput + HasNamedMetadata, S: UsesInput + HasNamedMetadata,
C: CanTrack + AsRef<O>,
{ {
/// Create new `MapFeedback` /// Create new `MapFeedback`
#[must_use] #[must_use]
pub fn new(map_observer: &O) -> Self { pub fn new(map_observer: &C) -> Self {
let map_observer = map_observer.as_ref();
Self { Self {
indexes: false, novelties: if C::NOVELTIES { Some(vec![]) } else { None },
novelties: None,
name: map_observer.name().to_string(), name: map_observer.name().to_string(),
observer_name: map_observer.name().to_string(), observer_name: map_observer.name().to_string(),
stats_name: create_stats_name(map_observer.name()), stats_name: create_stats_name(map_observer.name()),
@ -704,40 +714,14 @@ where
} }
} }
/// Create new `MapFeedback` specifying if it must track indexes of used entries and/or novelties
#[must_use]
pub fn tracking(map_observer: &O, track_indexes: bool, track_novelties: bool) -> Self {
Self {
indexes: track_indexes,
novelties: if track_novelties { Some(vec![]) } else { None },
name: map_observer.name().to_string(),
observer_name: map_observer.name().to_string(),
stats_name: create_stats_name(map_observer.name()),
phantom: PhantomData,
}
}
/// Create new `MapFeedback`
#[must_use]
pub fn with_names(name: &'static str, observer_name: &'static str) -> Self {
Self {
indexes: false,
novelties: None,
name: name.to_string(),
observer_name: observer_name.to_string(),
stats_name: create_stats_name(name),
phantom: PhantomData,
}
}
/// Creating a new `MapFeedback` with a specific name. This is usefully whenever the same /// Creating a new `MapFeedback` with a specific name. This is usefully whenever the same
/// feedback is needed twice, but with a different history. Using `new()` always results in the /// feedback is needed twice, but with a different history. Using `new()` always results in the
/// same name and therefore also the same history. /// same name and therefore also the same history.
#[must_use] #[must_use]
pub fn with_name(name: &'static str, map_observer: &O) -> Self { pub fn with_name(name: &'static str, map_observer: &C) -> Self {
let map_observer = map_observer.as_ref();
Self { Self {
indexes: false, novelties: if C::NOVELTIES { Some(vec![]) } else { None },
novelties: None,
name: name.to_string(), name: name.to_string(),
observer_name: map_observer.name().to_string(), observer_name: map_observer.name().to_string(),
stats_name: create_stats_name(name), stats_name: create_stats_name(name),
@ -745,24 +729,6 @@ where
} }
} }
/// Create new `MapFeedback` specifying if it must track indexes of used entries and/or novelties
#[must_use]
pub fn with_names_tracking(
name: &'static str,
observer_name: &'static str,
track_indexes: bool,
track_novelties: bool,
) -> Self {
Self {
indexes: track_indexes,
novelties: if track_novelties { Some(vec![]) } else { None },
observer_name: observer_name.to_string(),
stats_name: create_stats_name(name),
name: name.to_string(),
phantom: PhantomData,
}
}
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]
#[allow(clippy::needless_range_loop)] #[allow(clippy::needless_range_loop)]
#[allow(clippy::trivially_copy_pass_by_ref)] #[allow(clippy::trivially_copy_pass_by_ref)]
@ -780,7 +746,10 @@ where
{ {
let mut interesting = false; let mut interesting = false;
// TODO Replace with match_name_type when stable // TODO Replace with match_name_type when stable
let observer = observers.match_name::<O>(&self.observer_name).unwrap(); let observer = observers
.match_name::<C>(&self.observer_name)
.unwrap()
.as_ref();
let map_state = state let map_state = state
.named_metadata_map_mut() .named_metadata_map_mut()

View File

@ -80,10 +80,347 @@ fn hash_slice<T>(slice: &[T]) -> u64 {
hasher.finish() hasher.finish()
} }
/// Trait marker which indicates that this [`MapObserver`] is tracked for indices or novelties.
/// Implementors of feedbacks similar to [`crate::feedbacks::MapFeedback`] may wish to use this to
/// ensure that edge metadata is recorded as is appropriate for the provided observer.
///
/// If you get a type constraint failure for your map due to this type being unfulfilled, you must
/// call [`CanTrack::track_indices`] or [`CanTrack::track_novelties`] **at
/// the initialisation site of your map**.
///
/// This trait allows various components which interact with map metadata to ensure that the
/// information they need is actually recorded by the map feedback.
/// For example, if you are using [`crate::schedulers::MinimizerScheduler`]:
/// ```
/// # use libafl::corpus::InMemoryCorpus;
/// # use libafl::feedbacks::{Feedback, MapFeedbackMetadata};
/// use libafl::feedbacks::MaxMapFeedback;
/// # use libafl::inputs::BytesInput;
/// use libafl::observers::{StdMapObserver, CanTrack};
/// use libafl::schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler};
/// # use libafl::state::StdState;
/// # use libafl_bolts::serdeany::RegistryBuilder;
/// #
/// # #[cfg(any(not(feature = "serdeany_autoreg"), miri))]
/// # unsafe { MapFeedbackMetadata::<u8>::register() }
/// # #[cfg(not(feature = "std"))]
/// # #[no_mangle]
/// # pub extern "C" fn external_current_millis() -> u64 { 0 }
///
/// use libafl_bolts::ownedref::OwnedMutSlice;
/// # use libafl_bolts::rands::StdRand;
///
/// // initialise your map as necessary
/// let edges_observer = StdMapObserver::from_ownedref("edges", OwnedMutSlice::from(vec![0u8; 16]));
/// // inform the feedback to track indices (required by IndexesLenTimeMinimizerScheduler), but not novelties
/// // this *MUST* be done before it is passed to MaxMapFeedback!
/// let edges_observer = edges_observer.track_indices();
///
/// // init the feedback
/// let mut feedback = MaxMapFeedback::new(&edges_observer);
/// #
/// # // init the state
/// # let mut state = StdState::new(
/// # StdRand::with_seed(0),
/// # InMemoryCorpus::<BytesInput>::new(),
/// # InMemoryCorpus::new(),
/// # &mut feedback,
/// # &mut ()
/// # ).unwrap();
/// # feedback.init_state(&mut state).unwrap();
///
/// let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
/// # scheduler.cull(&state).unwrap();
/// ```
///
/// [`MapObserver`] implementors: see [`StdMapObserver`] for an example implementation.
pub trait CanTrack {
/// The resulting type of enabling index tracking.
type WithIndexTracking: CanTrack;
/// The resulting type of enabling novelty tracking.
type WithNoveltiesTracking: CanTrack;
/// Whether indices should be tracked for this [`MapObserver`].
const INDICES: bool;
/// Whether novelties should be tracked for this [`MapObserver`].
const NOVELTIES: bool;
/// Convert this map observer into one that tracks indices.
fn track_indices(self) -> Self::WithIndexTracking;
/// Convert this map observer into one that tracks novelties.
fn track_novelties(self) -> Self::WithNoveltiesTracking;
}
/// Struct which wraps [`MapObserver`] instances to explicitly give them tracking data.
///
/// # Safety
///
/// This is a bit of a magic structure. We pass it to the observer tuple as itself, but when its
/// referred to with `match_name`, there is a cast from this type to its inner type. This is
/// *guaranteed to be safe* by `#[repr(transparent)]`.
#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
pub struct ExplicitTracking<T, const ITH: bool, const NTH: bool>(T);
impl<T, const ITH: bool, const NTH: bool> CanTrack for ExplicitTracking<T, ITH, NTH> {
type WithIndexTracking = ExplicitTracking<T, true, NTH>;
type WithNoveltiesTracking = ExplicitTracking<T, ITH, true>;
const INDICES: bool = ITH;
const NOVELTIES: bool = NTH;
fn track_indices(self) -> Self::WithIndexTracking {
ExplicitTracking::<T, true, NTH>(self.0)
}
fn track_novelties(self) -> Self::WithNoveltiesTracking {
ExplicitTracking::<T, ITH, true>(self.0)
}
}
impl<T, const ITH: bool, const NTH: bool> AsRef<T> for ExplicitTracking<T, ITH, NTH> {
fn as_ref(&self) -> &T {
&self.0
}
}
impl<T, const ITH: bool, const NTH: bool> AsMut<T> for ExplicitTracking<T, ITH, NTH> {
fn as_mut(&mut self) -> &mut T {
&mut self.0
}
}
impl<T, const ITH: bool, const NTH: bool> Named for ExplicitTracking<T, ITH, NTH>
where
T: Named,
{
fn name(&self) -> &str {
self.0.name()
}
}
impl<S, T, const ITH: bool, const NTH: bool> Observer<S> for ExplicitTracking<T, ITH, NTH>
where
S: UsesInput,
T: Observer<S>,
{
fn flush(&mut self) -> Result<(), Error> {
self.0.flush()
}
fn pre_exec(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
self.0.pre_exec(state, input)
}
fn post_exec(
&mut self,
state: &mut S,
input: &S::Input,
exit_kind: &ExitKind,
) -> Result<(), Error> {
self.0.post_exec(state, input, exit_kind)
}
fn pre_exec_child(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> {
self.0.pre_exec_child(state, input)
}
fn post_exec_child(
&mut self,
state: &mut S,
input: &S::Input,
exit_kind: &ExitKind,
) -> Result<(), Error> {
self.0.post_exec_child(state, input, exit_kind)
}
fn observes_stdout(&self) -> bool {
self.0.observes_stdout()
}
fn observes_stderr(&self) -> bool {
self.0.observes_stderr()
}
fn observe_stdout(&mut self, stdout: &[u8]) {
self.0.observe_stdout(stdout);
}
fn observe_stderr(&mut self, stderr: &[u8]) {
self.0.observe_stderr(stderr);
}
}
impl<S, T, OTA, OTB, const ITH: bool, const NTH: bool> DifferentialObserver<OTA, OTB, S>
for ExplicitTracking<T, ITH, NTH>
where
OTA: ObserversTuple<S>,
OTB: ObserversTuple<S>,
S: UsesInput,
T: DifferentialObserver<OTA, OTB, S>,
{
fn pre_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> {
self.as_mut().pre_observe_first(observers)
}
fn post_observe_first(&mut self, observers: &mut OTA) -> Result<(), Error> {
self.as_mut().post_observe_first(observers)
}
fn pre_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> {
self.as_mut().pre_observe_second(observers)
}
fn post_observe_second(&mut self, observers: &mut OTB) -> Result<(), Error> {
self.as_mut().post_observe_second(observers)
}
}
/// Module which holds the necessary functions and types for map-relevant macros, namely
/// [`crate::require_index_tracking`] and [`crate::require_novelties_tracking`].
pub mod macros {
pub use const_format::{concatcp, str_repeat};
pub use const_panic::{concat_panic, FmtArg};
/// Use in the constructor of your component which requires index tracking of a
/// [`super::MapObserver`]. See [`super::CanTrack`] for details.
///
/// As an example, if you are developing the type `MyCustomScheduler<O>` which requires novelty
/// tracking, use this in your constructor:
/// ```
/// # use libafl::observers::{MapObserver, CanTrack};
/// # use libafl::require_index_tracking;
/// # use core::marker::PhantomData;
/// #
/// # struct MyCustomScheduler<C, O> {
/// # phantom: PhantomData<(C, O)>,
/// # }
/// #
/// impl<C, O> MyCustomScheduler<C, O> where O: MapObserver, C: CanTrack + AsRef<O> {
/// pub fn new(obs: &C) -> Self {
/// require_index_tracking!("MyCustomScheduler", C);
/// todo!("Construct your type")
/// }
/// }
/// ```
#[macro_export]
macro_rules! require_index_tracking {
($name: literal, $obs: ident) => {
struct SanityCheck<O: $crate::observers::CanTrack> {
phantom: ::core::marker::PhantomData<O>,
}
impl<O: $crate::observers::CanTrack> SanityCheck<O> {
#[rustfmt::skip]
const MESSAGE: &'static str = {
const LINE_OFFSET: usize = line!().ilog10() as usize + 2;
const SPACING: &str = $crate::observers::map::macros::str_repeat!(" ", LINE_OFFSET);
$crate::observers::map::macros::concatcp!(
"\n",
SPACING, "|\n",
SPACING, "= note: index tracking is required by ", $name, "\n",
SPACING, "= note: see the documentation of CanTrack for details\n",
SPACING, "|\n",
SPACING, "= hint: call `.track_indices()` on the map observer passed to ", $name, " at the point where it is defined\n",
SPACING, "|\n",
SPACING, "| ",
)
};
const TRACKING_SANITY: bool = {
if !O::INDICES {
panic!("{}", Self::MESSAGE)
} else {
true
}
};
#[inline(always)]
fn check_sanity() {
if !Self::TRACKING_SANITY {
unreachable!("{}", Self::MESSAGE);
}
}
}
SanityCheck::<$obs>::check_sanity(); // check that tracking is enabled for this map
};
}
/// Use in the constructor of your component which requires novelties tracking of a
/// [`super::MapObserver`]. See [`super::CanTrack`] for details on the concept.
///
/// As an example, if you are developing the type `MyCustomScheduler<O>` which requires novelty
/// tracking, use this in your constructor:
/// ```
/// # use libafl::observers::{MapObserver, CanTrack};
/// # use libafl::require_novelties_tracking;
/// # use core::marker::PhantomData;
/// #
/// # struct MyCustomScheduler<C, O> {
/// # phantom: PhantomData<(C, O)>,
/// # }
/// #
/// impl<C, O> MyCustomScheduler<C, O> where O: MapObserver, C: CanTrack + AsRef<O> {
/// pub fn new(obs: &C) -> Self {
/// require_novelties_tracking!("MyCustomScheduler", C);
/// todo!("Construct your type")
/// }
/// }
/// ```
#[macro_export]
macro_rules! require_novelties_tracking {
($name: literal, $obs: ident) => {
struct SanityCheck<O: $crate::observers::CanTrack> {
phantom: ::core::marker::PhantomData<O>,
}
impl<O: $crate::observers::CanTrack> SanityCheck<O> {
#[rustfmt::skip]
const MESSAGE: &'static str = {
const LINE_OFFSET: usize = line!().ilog10() as usize + 2;
const SPACING: &str =
$crate::observers::map::macros::str_repeat!(" ", LINE_OFFSET);
$crate::observers::map::macros::concatcp!(
"\n",
SPACING, "|\n",
SPACING, "= note: novelty tracking is required by ", $name, "\n",
SPACING, "= note: see the documentation of CanTrack for details\n",
SPACING, "|\n",
SPACING, "= hint: call `.track_novelties()` on the map observer passed to ", $name, " at the point where it is defined\n",
SPACING, "|\n",
SPACING, "| ",
)
};
const TRACKING_SANITY: bool = {
if !O::NOVELTIES {
panic!("{}", Self::MESSAGE)
} else {
true
}
};
#[inline(always)]
fn check_sanity() {
if !Self::TRACKING_SANITY {
unreachable!("{}", Self::MESSAGE);
}
}
}
SanityCheck::<$obs>::check_sanity(); // check that tracking is enabled for this map
};
}
}
/// A [`MapObserver`] observes the static map, as oftentimes used for AFL-like coverage information /// A [`MapObserver`] observes the static map, as oftentimes used for AFL-like coverage information
/// ///
/// When referring to this type in a constraint (e.g. `O: MapObserver`), ensure that you only refer
/// to instances of a second type, e.g. `C: AsRef<O>` or `A: AsMut<O>`. Map observer instances are
/// passed around in a way that may be potentially wrapped by e.g. [`ExplicitTracking`] as a way to
/// encode metadata into the type. This is an unfortunate additional requirement that we can't get
/// around without specialization.
///
/// See [`crate::require_index_tracking`] for an example of how to do so.
///
/// TODO: enforce `iter() -> AssociatedTypeIter` when generic associated types stabilize /// TODO: enforce `iter() -> AssociatedTypeIter` when generic associated types stabilize
pub trait MapObserver: HasLen + Named + Serialize + serde::de::DeserializeOwned pub trait MapObserver:
HasLen + Named + Serialize + serde::de::DeserializeOwned + AsRef<Self> + AsMut<Self>
// where // where
// for<'it> &'it Self: IntoIterator<Item = &'it Self::Entry> // for<'it> &'it Self: IntoIterator<Item = &'it Self::Entry>
{ {
@ -118,6 +455,24 @@ pub trait MapObserver: HasLen + Named + Serialize + serde::de::DeserializeOwned
fn how_many_set(&self, indexes: &[usize]) -> usize; fn how_many_set(&self, indexes: &[usize]) -> usize;
} }
impl<M> CanTrack for M
where
M: MapObserver,
{
type WithIndexTracking = ExplicitTracking<Self, true, false>;
type WithNoveltiesTracking = ExplicitTracking<Self, false, true>;
const INDICES: bool = false;
const NOVELTIES: bool = false;
fn track_indices(self) -> Self::WithIndexTracking {
ExplicitTracking::<Self, true, false>(self)
}
fn track_novelties(self) -> Self::WithNoveltiesTracking {
ExplicitTracking::<Self, false, true>(self)
}
}
/// A Simple iterator calling `MapObserver::get` /// A Simple iterator calling `MapObserver::get`
#[derive(Debug)] #[derive(Debug)]
pub struct MapObserverSimpleIterator<'a, O> pub struct MapObserverSimpleIterator<'a, O>
@ -346,6 +701,24 @@ where
} }
} }
impl<'a, T, const DIFFERENTIAL: bool> AsRef<Self> for StdMapObserver<'a, T, DIFFERENTIAL>
where
T: Default + Copy + 'static + Serialize,
{
fn as_ref(&self) -> &Self {
self
}
}
impl<'a, T, const DIFFERENTIAL: bool> AsMut<Self> for StdMapObserver<'a, T, DIFFERENTIAL>
where
T: Default + Copy + 'static + Serialize,
{
fn as_mut(&mut self) -> &mut Self {
self
}
}
impl<'a, T, const DIFFERENTIAL: bool> MapObserver for StdMapObserver<'a, T, DIFFERENTIAL> impl<'a, T, const DIFFERENTIAL: bool> MapObserver for StdMapObserver<'a, T, DIFFERENTIAL>
where where
T: Bounded T: Bounded
@ -455,6 +828,7 @@ where
self.map.as_slice() self.map.as_slice()
} }
} }
impl<'a, T, const DIFFERENTIAL: bool> AsMutSlice for StdMapObserver<'a, T, DIFFERENTIAL> impl<'a, T, const DIFFERENTIAL: bool> AsMutSlice for StdMapObserver<'a, T, DIFFERENTIAL>
where where
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
@ -830,6 +1204,24 @@ where
} }
} }
impl<'a, T, const N: usize> AsRef<Self> for ConstMapObserver<'a, T, N>
where
T: Default + Copy + 'static + Serialize,
{
fn as_ref(&self) -> &Self {
self
}
}
impl<'a, T, const N: usize> AsMut<Self> for ConstMapObserver<'a, T, N>
where
T: Default + Copy + 'static + Serialize,
{
fn as_mut(&mut self) -> &mut Self {
self
}
}
impl<'a, T, const N: usize> MapObserver for ConstMapObserver<'a, T, N> impl<'a, T, const N: usize> MapObserver for ConstMapObserver<'a, T, N>
where where
T: Bounded T: Bounded
@ -922,6 +1314,7 @@ where
self.map.as_slice() self.map.as_slice()
} }
} }
impl<'a, T, const N: usize> AsMutSlice for ConstMapObserver<'a, T, N> impl<'a, T, const N: usize> AsMutSlice for ConstMapObserver<'a, T, N>
where where
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
@ -1142,6 +1535,24 @@ where
} }
} }
impl<'a, T> AsRef<Self> for VariableMapObserver<'a, T>
where
T: Default + Copy + 'static + Serialize + PartialEq + Bounded,
{
fn as_ref(&self) -> &Self {
self
}
}
impl<'a, T> AsMut<Self> for VariableMapObserver<'a, T>
where
T: Default + Copy + 'static + Serialize + PartialEq + Bounded,
{
fn as_mut(&mut self) -> &mut Self {
self
}
}
impl<'a, T> MapObserver for VariableMapObserver<'a, T> impl<'a, T> MapObserver for VariableMapObserver<'a, T>
where where
T: Bounded T: Bounded
@ -1243,6 +1654,7 @@ where
&self.map.as_slice()[..cnt] &self.map.as_slice()[..cnt]
} }
} }
impl<'a, T> AsMutSlice for VariableMapObserver<'a, T> impl<'a, T> AsMutSlice for VariableMapObserver<'a, T>
where where
T: 'static T: 'static
@ -1305,8 +1717,8 @@ where
/// Map observer with AFL-like hitcounts postprocessing /// Map observer with AFL-like hitcounts postprocessing
/// ///
/// [`MapObserver`]s that are not slice-backed, /// [`MapObserver`]s that are not slice-backed, such as [`MultiMapObserver`], can use
/// such as [`MultiMapObserver`], can use [`HitcountsIterableMapObserver`] instead. /// [`HitcountsIterableMapObserver`] instead.
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "M: serde::de::DeserializeOwned")] #[serde(bound = "M: serde::de::DeserializeOwned")]
pub struct HitcountsMapObserver<M> pub struct HitcountsMapObserver<M>
@ -1396,6 +1808,24 @@ where
} }
} }
impl<M> AsRef<Self> for HitcountsMapObserver<M>
where
M: MapObserver<Entry = u8>,
{
fn as_ref(&self) -> &Self {
self
}
}
impl<M> AsMut<Self> for HitcountsMapObserver<M>
where
M: MapObserver<Entry = u8>,
{
fn as_mut(&mut self) -> &mut Self {
self
}
}
impl<M> MapObserver for HitcountsMapObserver<M> impl<M> MapObserver for HitcountsMapObserver<M>
where where
M: MapObserver<Entry = u8>, M: MapObserver<Entry = u8>,
@ -1478,7 +1908,7 @@ where
impl<M> HitcountsMapObserver<M> impl<M> HitcountsMapObserver<M>
where where
M: Serialize + serde::de::DeserializeOwned, M: MapObserver,
{ {
/// Creates a new [`MapObserver`] /// Creates a new [`MapObserver`]
pub fn new(base: M) -> Self { pub fn new(base: M) -> Self {
@ -1645,6 +2075,26 @@ where
} }
} }
impl<M> AsRef<Self> for HitcountsIterableMapObserver<M>
where
M: MapObserver<Entry = u8>,
for<'it> M: AsIterMut<'it, Item = u8>,
{
fn as_ref(&self) -> &Self {
self
}
}
impl<M> AsMut<Self> for HitcountsIterableMapObserver<M>
where
M: MapObserver<Entry = u8>,
for<'it> M: AsIterMut<'it, Item = u8>,
{
fn as_mut(&mut self) -> &mut Self {
self
}
}
impl<M> MapObserver for HitcountsIterableMapObserver<M> impl<M> MapObserver for HitcountsIterableMapObserver<M>
where where
M: MapObserver<Entry = u8>, M: MapObserver<Entry = u8>,
@ -1714,6 +2164,7 @@ where
self.base.as_slice() self.base.as_slice()
} }
} }
impl<M> AsMutSlice for HitcountsIterableMapObserver<M> impl<M> AsMutSlice for HitcountsIterableMapObserver<M>
where where
M: MapObserver + AsMutSlice, M: MapObserver + AsMutSlice,
@ -1890,6 +2341,24 @@ where
} }
} }
impl<'a, T, const DIFFERENTIAL: bool> AsRef<Self> for MultiMapObserver<'a, T, DIFFERENTIAL>
where
T: 'static + Default + Copy + Serialize + Debug,
{
fn as_ref(&self) -> &Self {
self
}
}
impl<'a, T, const DIFFERENTIAL: bool> AsMut<Self> for MultiMapObserver<'a, T, DIFFERENTIAL>
where
T: 'static + Default + Copy + Serialize + Debug,
{
fn as_mut(&mut self) -> &mut Self {
self
}
}
impl<'a, T, const DIFFERENTIAL: bool> MapObserver for MultiMapObserver<'a, T, DIFFERENTIAL> impl<'a, T, const DIFFERENTIAL: bool> MapObserver for MultiMapObserver<'a, T, DIFFERENTIAL>
where where
T: 'static T: 'static
@ -2245,6 +2714,24 @@ where
} }
} }
impl<T> AsRef<Self> for OwnedMapObserver<T>
where
T: 'static + Default + Copy + Serialize,
{
fn as_ref(&self) -> &Self {
self
}
}
impl<T> AsMut<Self> for OwnedMapObserver<T>
where
T: 'static + Default + Copy + Serialize,
{
fn as_mut(&mut self) -> &mut Self {
self
}
}
impl<T> MapObserver for OwnedMapObserver<T> impl<T> MapObserver for OwnedMapObserver<T>
where where
T: 'static T: 'static

View File

@ -11,7 +11,7 @@ use crate::{
corpus::{Corpus, CorpusId}, corpus::{Corpus, CorpusId},
feedbacks::MapIndexesMetadata, feedbacks::MapIndexesMetadata,
inputs::UsesInput, inputs::UsesInput,
observers::ObserversTuple, observers::{CanTrack, ObserversTuple},
schedulers::{ schedulers::{
minimizer::{IsFavoredMetadata, MinimizerScheduler, DEFAULT_SKIP_NON_FAVORED_PROB}, minimizer::{IsFavoredMetadata, MinimizerScheduler, DEFAULT_SKIP_NON_FAVORED_PROB},
LenTimeMulTestcaseScore, Scheduler, LenTimeMulTestcaseScore, Scheduler,
@ -106,7 +106,7 @@ impl TopAccountingMetadata {
/// A minimizer scheduler using coverage accounting /// A minimizer scheduler using coverage accounting
#[derive(Debug)] #[derive(Debug)]
pub struct CoverageAccountingScheduler<'a, CS> pub struct CoverageAccountingScheduler<'a, CS, O>
where where
CS: UsesState, CS: UsesState,
CS::State: Debug, CS::State: Debug,
@ -117,10 +117,11 @@ where
CS, CS,
LenTimeMulTestcaseScore<<CS as UsesState>::State>, LenTimeMulTestcaseScore<<CS as UsesState>::State>,
MapIndexesMetadata, MapIndexesMetadata,
O,
>, >,
} }
impl<'a, CS> UsesState for CoverageAccountingScheduler<'a, CS> impl<'a, CS, O> UsesState for CoverageAccountingScheduler<'a, CS, O>
where where
CS: UsesState, CS: UsesState,
CS::State: Debug, CS::State: Debug,
@ -128,11 +129,12 @@ where
type State = CS::State; type State = CS::State;
} }
impl<'a, CS> Scheduler for CoverageAccountingScheduler<'a, CS> impl<'a, CS, O> Scheduler for CoverageAccountingScheduler<'a, CS, O>
where where
CS: Scheduler, CS: Scheduler,
CS::State: HasCorpus + HasMetadata + HasRand + Debug, CS::State: HasCorpus + HasMetadata + HasRand + Debug,
<CS::State as UsesInput>::Input: HasLen, <CS::State as UsesInput>::Input: HasLen,
O: CanTrack,
{ {
fn on_add(&mut self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> { fn on_add(&mut self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> {
self.update_accounting_score(state, idx)?; self.update_accounting_score(state, idx)?;
@ -190,11 +192,12 @@ where
} }
} }
impl<'a, CS> CoverageAccountingScheduler<'a, CS> impl<'a, CS, O> CoverageAccountingScheduler<'a, CS, O>
where where
CS: Scheduler, CS: Scheduler,
CS::State: HasCorpus + HasMetadata + HasRand + Debug, CS::State: HasCorpus + HasMetadata + HasRand + Debug,
<CS::State as UsesInput>::Input: HasLen, <CS::State as UsesInput>::Input: HasLen,
O: CanTrack,
{ {
/// Update the `Corpus` score /// Update the `Corpus` score
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
@ -307,7 +310,9 @@ where
/// Creates a new [`CoverageAccountingScheduler`] that wraps a `base` [`Scheduler`] /// Creates a new [`CoverageAccountingScheduler`] that wraps a `base` [`Scheduler`]
/// and has a default probability to skip non-faved Testcases of [`DEFAULT_SKIP_NON_FAVORED_PROB`]. /// and has a default probability to skip non-faved Testcases of [`DEFAULT_SKIP_NON_FAVORED_PROB`].
pub fn new(state: &mut CS::State, base: CS, accounting_map: &'a [u32]) -> Self { ///
/// Provide the observer responsible for determining new indexes.
pub fn new(observer: &O, state: &mut CS::State, base: CS, accounting_map: &'a [u32]) -> Self {
match state.metadata_map().get::<TopAccountingMetadata>() { match state.metadata_map().get::<TopAccountingMetadata>() {
Some(meta) => { Some(meta) => {
if meta.max_accounting.len() != accounting_map.len() { if meta.max_accounting.len() != accounting_map.len() {
@ -320,14 +325,17 @@ where
} }
Self { Self {
accounting_map, accounting_map,
inner: MinimizerScheduler::new(base), inner: MinimizerScheduler::new(observer, base),
skip_non_favored_prob: DEFAULT_SKIP_NON_FAVORED_PROB, skip_non_favored_prob: DEFAULT_SKIP_NON_FAVORED_PROB,
} }
} }
/// Creates a new [`CoverageAccountingScheduler`] that wraps a `base` [`Scheduler`] /// Creates a new [`CoverageAccountingScheduler`] that wraps a `base` [`Scheduler`]
/// and has a non-default probability to skip non-faved Testcases using (`skip_non_favored_prob`). /// and has a non-default probability to skip non-faved Testcases using (`skip_non_favored_prob`).
///
/// Provide the observer responsible for determining new indexes.
pub fn with_skip_prob( pub fn with_skip_prob(
observer: &O,
state: &mut CS::State, state: &mut CS::State,
base: CS, base: CS,
skip_non_favored_prob: u64, skip_non_favored_prob: u64,
@ -345,7 +353,7 @@ where
} }
Self { Self {
accounting_map, accounting_map,
inner: MinimizerScheduler::with_skip_prob(base, skip_non_favored_prob), inner: MinimizerScheduler::with_skip_prob(observer, base, skip_non_favored_prob),
skip_non_favored_prob, skip_non_favored_prob,
} }
} }

View File

@ -12,7 +12,8 @@ use crate::{
corpus::{Corpus, CorpusId, Testcase}, corpus::{Corpus, CorpusId, Testcase},
feedbacks::MapIndexesMetadata, feedbacks::MapIndexesMetadata,
inputs::UsesInput, inputs::UsesInput,
observers::ObserversTuple, observers::{CanTrack, ObserversTuple},
require_index_tracking,
schedulers::{LenTimeMulTestcaseScore, RemovableScheduler, Scheduler, TestcaseScore}, schedulers::{LenTimeMulTestcaseScore, RemovableScheduler, Scheduler, TestcaseScore},
state::{HasCorpus, HasRand, UsesState}, state::{HasCorpus, HasRand, UsesState},
Error, HasMetadata, Error, HasMetadata,
@ -70,26 +71,27 @@ impl Default for TopRatedsMetadata {
/// corpus that exercise all the requested features (e.g. all the coverage seen so far) /// corpus that exercise all the requested features (e.g. all the coverage seen so far)
/// prioritizing [`Testcase`]`s` using [`TestcaseScore`] /// prioritizing [`Testcase`]`s` using [`TestcaseScore`]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct MinimizerScheduler<CS, F, M> { pub struct MinimizerScheduler<CS, F, M, O> {
base: CS, base: CS,
skip_non_favored_prob: u64, skip_non_favored_prob: u64,
remove_metadata: bool, remove_metadata: bool,
phantom: PhantomData<(F, M)>, phantom: PhantomData<(F, M, O)>,
} }
impl<CS, F, M> UsesState for MinimizerScheduler<CS, F, M> impl<CS, F, M, O> UsesState for MinimizerScheduler<CS, F, M, O>
where where
CS: UsesState, CS: UsesState,
{ {
type State = CS::State; type State = CS::State;
} }
impl<CS, F, M> RemovableScheduler for MinimizerScheduler<CS, F, M> impl<CS, F, M, O> RemovableScheduler for MinimizerScheduler<CS, F, M, O>
where where
CS: RemovableScheduler, CS: RemovableScheduler,
F: TestcaseScore<CS::State>, F: TestcaseScore<CS::State>,
M: AsSlice<Entry = usize> + SerdeAny + HasRefCnt, M: AsSlice<Entry = usize> + SerdeAny + HasRefCnt,
CS::State: HasCorpus + HasMetadata + HasRand, CS::State: HasCorpus + HasMetadata + HasRand,
O: CanTrack,
{ {
/// Replaces the testcase at the given idx /// Replaces the testcase at the given idx
fn on_replace( fn on_replace(
@ -191,12 +193,13 @@ where
} }
} }
impl<CS, F, M> Scheduler for MinimizerScheduler<CS, F, M> impl<CS, F, M, O> Scheduler for MinimizerScheduler<CS, F, M, O>
where where
CS: Scheduler, CS: Scheduler,
F: TestcaseScore<CS::State>, F: TestcaseScore<CS::State>,
M: AsSlice<Entry = usize> + SerdeAny + HasRefCnt, M: AsSlice<Entry = usize> + SerdeAny + HasRefCnt,
CS::State: HasCorpus + HasMetadata + HasRand, CS::State: HasCorpus + HasMetadata + HasRand,
O: CanTrack,
{ {
/// Called when a [`Testcase`] is added to the corpus /// Called when a [`Testcase`] is added to the corpus
fn on_add(&mut self, state: &mut CS::State, idx: CorpusId) -> Result<(), Error> { fn on_add(&mut self, state: &mut CS::State, idx: CorpusId) -> Result<(), Error> {
@ -246,12 +249,13 @@ where
} }
} }
impl<CS, F, M> MinimizerScheduler<CS, F, M> impl<CS, F, M, O> MinimizerScheduler<CS, F, M, O>
where where
CS: Scheduler, CS: Scheduler,
F: TestcaseScore<CS::State>, F: TestcaseScore<CS::State>,
M: AsSlice<Entry = usize> + SerdeAny + HasRefCnt, M: AsSlice<Entry = usize> + SerdeAny + HasRefCnt,
CS::State: HasCorpus + HasMetadata + HasRand, CS::State: HasCorpus + HasMetadata + HasRand,
O: CanTrack,
{ {
/// Update the [`Corpus`] score using the [`MinimizerScheduler`] /// Update the [`Corpus`] score using the [`MinimizerScheduler`]
#[allow(clippy::unused_self)] #[allow(clippy::unused_self)]
@ -371,7 +375,10 @@ where
/// and has a default probability to skip non-faved [`Testcase`]s of [`DEFAULT_SKIP_NON_FAVORED_PROB`]. /// and has a default probability to skip non-faved [`Testcase`]s of [`DEFAULT_SKIP_NON_FAVORED_PROB`].
/// This will remove the metadata `M` when it is no longer needed, after consumption. This might /// This will remove the metadata `M` when it is no longer needed, after consumption. This might
/// for example be a `MapIndexesMetadata`. /// for example be a `MapIndexesMetadata`.
pub fn new(base: CS) -> Self { ///
/// When calling, pass the edges observer which will provided the indexes to minimize over.
pub fn new(_observer: &O, base: CS) -> Self {
require_index_tracking!("MinimizerScheduler", O);
Self { Self {
base, base,
skip_non_favored_prob: DEFAULT_SKIP_NON_FAVORED_PROB, skip_non_favored_prob: DEFAULT_SKIP_NON_FAVORED_PROB,
@ -383,7 +390,10 @@ where
/// Creates a new [`MinimizerScheduler`] that wraps a `base` [`Scheduler`] /// Creates a new [`MinimizerScheduler`] that wraps a `base` [`Scheduler`]
/// and has a default probability to skip non-faved [`Testcase`]s of [`DEFAULT_SKIP_NON_FAVORED_PROB`]. /// and has a default probability to skip non-faved [`Testcase`]s of [`DEFAULT_SKIP_NON_FAVORED_PROB`].
/// This method will prevent the metadata `M` from being removed at the end of scoring. /// This method will prevent the metadata `M` from being removed at the end of scoring.
pub fn non_metadata_removing(base: CS) -> Self { ///
/// When calling, pass the edges observer which will provided the indexes to minimize over.
pub fn non_metadata_removing(_observer: &O, base: CS) -> Self {
require_index_tracking!("MinimizerScheduler", O);
Self { Self {
base, base,
skip_non_favored_prob: DEFAULT_SKIP_NON_FAVORED_PROB, skip_non_favored_prob: DEFAULT_SKIP_NON_FAVORED_PROB,
@ -394,7 +404,10 @@ where
/// Creates a new [`MinimizerScheduler`] that wraps a `base` [`Scheduler`] /// Creates a new [`MinimizerScheduler`] that wraps a `base` [`Scheduler`]
/// and has a non-default probability to skip non-faved [`Testcase`]s using (`skip_non_favored_prob`). /// and has a non-default probability to skip non-faved [`Testcase`]s using (`skip_non_favored_prob`).
pub fn with_skip_prob(base: CS, skip_non_favored_prob: u64) -> Self { ///
/// When calling, pass the edges observer which will provided the indexes to minimize over.
pub fn with_skip_prob(_observer: &O, base: CS, skip_non_favored_prob: u64) -> Self {
require_index_tracking!("MinimizerScheduler", O);
Self { Self {
base, base,
skip_non_favored_prob, skip_non_favored_prob,
@ -405,10 +418,14 @@ where
} }
/// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s`. /// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s`.
pub type LenTimeMinimizerScheduler<CS, M> = pub type LenTimeMinimizerScheduler<CS, M, O> =
MinimizerScheduler<CS, LenTimeMulTestcaseScore<<CS as UsesState>::State>, M>; MinimizerScheduler<CS, LenTimeMulTestcaseScore<<CS as UsesState>::State>, M, O>;
/// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s` /// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s`
/// that exercise all the entries registered in the [`MapIndexesMetadata`]. /// that exercise all the entries registered in the [`MapIndexesMetadata`].
pub type IndexesLenTimeMinimizerScheduler<CS> = pub type IndexesLenTimeMinimizerScheduler<CS, O> = MinimizerScheduler<
MinimizerScheduler<CS, LenTimeMulTestcaseScore<<CS as UsesState>::State>, MapIndexesMetadata>; CS,
LenTimeMulTestcaseScore<<CS as UsesState>::State>,
MapIndexesMetadata,
O,
>;

View File

@ -66,10 +66,11 @@ where
} }
/// Defines the common metadata operations for the AFL-style schedulers /// Defines the common metadata operations for the AFL-style schedulers
pub trait AflScheduler<O, S>: Scheduler pub trait AflScheduler<C, O, S>: Scheduler
where where
Self::State: HasCorpus + HasMetadata + HasTestcase, Self::State: HasCorpus + HasMetadata + HasTestcase,
O: MapObserver, O: MapObserver,
C: AsRef<O>,
{ {
/// Return the last hash /// Return the last hash
fn last_hash(&self) -> usize; fn last_hash(&self) -> usize;
@ -117,8 +118,9 @@ where
OT: ObserversTuple<Self::State>, OT: ObserversTuple<Self::State>,
{ {
let observer = observers let observer = observers
.match_name::<O>(self.map_observer_name()) .match_name::<C>(self.map_observer_name())
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?; .ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
.as_ref();
let mut hash = observer.hash() as usize; let mut hash = observer.hash() as usize;

View File

@ -6,6 +6,7 @@ use alloc::{
}; };
use core::{marker::PhantomData, time::Duration}; use core::{marker::PhantomData, time::Duration};
use libafl_bolts::Named;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
@ -170,24 +171,25 @@ pub enum PowerSchedule {
/// Note that this corpus is merely holding the metadata necessary for the power calculation /// Note that this corpus is merely holding the metadata necessary for the power calculation
/// and here we DON'T actually calculate the power (we do it in the stage) /// and here we DON'T actually calculate the power (we do it in the stage)
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PowerQueueScheduler<O, S> { pub struct PowerQueueScheduler<C, O, S> {
strat: PowerSchedule, strat: PowerSchedule,
map_observer_name: String, map_observer_name: String,
last_hash: usize, last_hash: usize,
phantom: PhantomData<(O, S)>, phantom: PhantomData<(C, O, S)>,
} }
impl<O, S> UsesState for PowerQueueScheduler<O, S> impl<C, O, S> UsesState for PowerQueueScheduler<C, O, S>
where where
S: State, S: State,
{ {
type State = S; type State = S;
} }
impl<O, S> RemovableScheduler for PowerQueueScheduler<O, S> impl<C, O, S> RemovableScheduler for PowerQueueScheduler<C, O, S>
where where
S: State + HasTestcase + HasMetadata + HasCorpus, S: State + HasTestcase + HasMetadata + HasCorpus,
O: MapObserver, O: MapObserver,
C: AsRef<O>,
{ {
/// This will *NOT* neutralize the effect of this removed testcase from the global data such as `SchedulerMetadata` /// This will *NOT* neutralize the effect of this removed testcase from the global data such as `SchedulerMetadata`
fn on_remove( fn on_remove(
@ -210,10 +212,11 @@ where
} }
} }
impl<O, S> AflScheduler<O, S> for PowerQueueScheduler<O, S> impl<C, O, S> AflScheduler<C, O, S> for PowerQueueScheduler<C, O, S>
where where
S: HasCorpus + HasMetadata + HasTestcase + State, S: HasCorpus + HasMetadata + HasTestcase + State,
O: MapObserver, O: MapObserver,
C: AsRef<O>,
{ {
fn last_hash(&self) -> usize { fn last_hash(&self) -> usize {
self.last_hash self.last_hash
@ -228,10 +231,11 @@ where
} }
} }
impl<O, S> Scheduler for PowerQueueScheduler<O, S> impl<C, O, S> Scheduler for PowerQueueScheduler<C, O, S>
where where
S: HasCorpus + HasMetadata + HasTestcase + State, S: HasCorpus + HasMetadata + HasTestcase + State,
O: MapObserver, O: MapObserver,
C: AsRef<O>,
{ {
/// Called when a [`Testcase`] is added to the corpus /// Called when a [`Testcase`] is added to the corpus
fn on_add(&mut self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> { fn on_add(&mut self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> {
@ -287,14 +291,15 @@ where
} }
} }
impl<O, S> PowerQueueScheduler<O, S> impl<C, O, S> PowerQueueScheduler<C, O, S>
where where
S: HasMetadata, S: HasMetadata,
O: MapObserver, O: MapObserver,
C: AsRef<O> + Named,
{ {
/// Create a new [`PowerQueueScheduler`] /// Create a new [`PowerQueueScheduler`]
#[must_use] #[must_use]
pub fn new(state: &mut S, map_observer: &O, strat: PowerSchedule) -> Self { pub fn new(state: &mut S, map_observer: &C, strat: PowerSchedule) -> Self {
if !state.has_metadata::<SchedulerMetadata>() { if !state.has_metadata::<SchedulerMetadata>() {
state.add_metadata::<SchedulerMetadata>(SchedulerMetadata::new(Some(strat))); state.add_metadata::<SchedulerMetadata>(SchedulerMetadata::new(Some(strat)));
} }

View File

@ -1,11 +1,11 @@
//! The queue corpus scheduler with weighted queue item selection from aflpp (`https://github.com/AFLplusplus/AFLplusplus/blob/1d4f1e48797c064ee71441ba555b29fc3f467983/src/afl-fuzz-queue.c#L32`) //! The queue corpus scheduler with weighted queue item selection [from AFL++](https://github.com/AFLplusplus/AFLplusplus/blob/1d4f1e48797c064ee71441ba555b29fc3f467983/src/afl-fuzz-queue.c#L32).
//! This queue corpus scheduler needs calibration stage. //! This queue corpus scheduler needs calibration stage.
use alloc::string::{String, ToString}; use alloc::string::{String, ToString};
use core::marker::PhantomData; use core::marker::PhantomData;
use hashbrown::HashMap; use hashbrown::HashMap;
use libafl_bolts::rands::Rand; use libafl_bolts::{rands::Rand, Named};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
@ -92,29 +92,30 @@ libafl_bolts::impl_serdeany!(WeightedScheduleMetadata);
/// A corpus scheduler using power schedules with weighted queue item selection algo. /// A corpus scheduler using power schedules with weighted queue item selection algo.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct WeightedScheduler<F, O, S> { pub struct WeightedScheduler<C, F, O, S> {
table_invalidated: bool, table_invalidated: bool,
strat: Option<PowerSchedule>, strat: Option<PowerSchedule>,
map_observer_name: String, map_observer_name: String,
last_hash: usize, last_hash: usize,
phantom: PhantomData<(F, O, S)>, phantom: PhantomData<(C, F, O, S)>,
} }
impl<F, O, S> WeightedScheduler<F, O, S> impl<C, F, O, S> WeightedScheduler<C, F, O, S>
where where
F: TestcaseScore<S>, F: TestcaseScore<S>,
O: MapObserver, O: MapObserver,
S: HasCorpus + HasMetadata + HasRand, S: HasCorpus + HasMetadata + HasRand,
C: AsRef<O> + Named,
{ {
/// Create a new [`WeightedScheduler`] without any power schedule /// Create a new [`WeightedScheduler`] without any power schedule
#[must_use] #[must_use]
pub fn new(state: &mut S, map_observer: &O) -> Self { pub fn new(state: &mut S, map_observer: &C) -> Self {
Self::with_schedule(state, map_observer, None) Self::with_schedule(state, map_observer, None)
} }
/// Create a new [`WeightedScheduler`] /// Create a new [`WeightedScheduler`]
#[must_use] #[must_use]
pub fn with_schedule(state: &mut S, map_observer: &O, strat: Option<PowerSchedule>) -> Self { pub fn with_schedule(state: &mut S, map_observer: &C, strat: Option<PowerSchedule>) -> Self {
let _ = state.metadata_or_insert_with(|| SchedulerMetadata::new(strat)); let _ = state.metadata_or_insert_with(|| SchedulerMetadata::new(strat));
let _ = state.metadata_or_insert_with(WeightedScheduleMetadata::new); let _ = state.metadata_or_insert_with(WeightedScheduleMetadata::new);
@ -218,18 +219,19 @@ where
} }
} }
impl<F, O, S> UsesState for WeightedScheduler<F, O, S> impl<C, F, O, S> UsesState for WeightedScheduler<C, F, O, S>
where where
S: State, S: State,
{ {
type State = S; type State = S;
} }
impl<F, O, S> RemovableScheduler for WeightedScheduler<F, O, S> impl<C, F, O, S> RemovableScheduler for WeightedScheduler<C, F, O, S>
where where
F: TestcaseScore<S>, F: TestcaseScore<S>,
O: MapObserver, O: MapObserver,
S: HasCorpus + HasMetadata + HasRand + HasTestcase + State, S: HasCorpus + HasMetadata + HasRand + HasTestcase + State,
C: AsRef<O> + Named,
{ {
/// This will *NOT* neutralize the effect of this removed testcase from the global data such as `SchedulerMetadata` /// This will *NOT* neutralize the effect of this removed testcase from the global data such as `SchedulerMetadata`
fn on_remove( fn on_remove(
@ -254,11 +256,12 @@ where
} }
} }
impl<F, O, S> AflScheduler<O, S> for WeightedScheduler<F, O, S> impl<C, F, O, S> AflScheduler<C, O, S> for WeightedScheduler<C, F, O, S>
where where
F: TestcaseScore<S>, F: TestcaseScore<S>,
S: HasCorpus + HasMetadata + HasTestcase + HasRand + State,
O: MapObserver, O: MapObserver,
S: HasCorpus + HasMetadata + HasTestcase + HasRand + State,
C: AsRef<O> + Named,
{ {
fn last_hash(&self) -> usize { fn last_hash(&self) -> usize {
self.last_hash self.last_hash
@ -273,11 +276,12 @@ where
} }
} }
impl<F, O, S> Scheduler for WeightedScheduler<F, O, S> impl<C, F, O, S> Scheduler for WeightedScheduler<C, F, O, S>
where where
F: TestcaseScore<S>, F: TestcaseScore<S>,
O: MapObserver, O: MapObserver,
S: HasCorpus + HasMetadata + HasRand + HasTestcase + State, S: HasCorpus + HasMetadata + HasRand + HasTestcase + State,
C: AsRef<O> + Named,
{ {
/// Called when a [`Testcase`] is added to the corpus /// Called when a [`Testcase`] is added to the corpus
fn on_add(&mut self, state: &mut S, idx: CorpusId) -> Result<(), Error> { fn on_add(&mut self, state: &mut S, idx: CorpusId) -> Result<(), Error> {
@ -356,5 +360,5 @@ where
} }
} }
/// The standard corpus weight, same as aflpp /// The standard corpus weight, same as in `AFL++`
pub type StdWeightedScheduler<O, S> = WeightedScheduler<CorpusWeightTestcaseScore<S>, O, S>; pub type StdWeightedScheduler<C, O, S> = WeightedScheduler<C, CorpusWeightTestcaseScore<S>, O, S>;

View File

@ -64,31 +64,32 @@ impl UnstableEntriesMetadata {
/// The calibration stage will measure the average exec time and the target's stability for this input. /// The calibration stage will measure the average exec time and the target's stability for this input.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct CalibrationStage<O, OT, S> { pub struct CalibrationStage<C, O, OT, S> {
map_observer_name: String, map_observer_name: String,
map_name: String, map_name: String,
stage_max: usize, stage_max: usize,
/// If we should track stability /// If we should track stability
track_stability: bool, track_stability: bool,
restart_helper: ExecutionCountRestartHelper, restart_helper: ExecutionCountRestartHelper,
phantom: PhantomData<(O, OT, S)>, phantom: PhantomData<(C, O, OT, S)>,
} }
const CAL_STAGE_START: usize = 4; // AFL++'s CAL_CYCLES_FAST + 1 const CAL_STAGE_START: usize = 4; // AFL++'s CAL_CYCLES_FAST + 1
const CAL_STAGE_MAX: usize = 8; // AFL++'s CAL_CYCLES + 1 const CAL_STAGE_MAX: usize = 8; // AFL++'s CAL_CYCLES + 1
impl<O, OT, S> UsesState for CalibrationStage<O, OT, S> impl<C, O, OT, S> UsesState for CalibrationStage<C, O, OT, S>
where where
S: State, S: State,
{ {
type State = S; type State = S;
} }
impl<E, EM, O, OT, Z> Stage<E, EM, Z> for CalibrationStage<O, OT, E::State> impl<C, E, EM, O, OT, Z> Stage<E, EM, Z> for CalibrationStage<C, O, OT, E::State>
where where
E: Executor<EM, Z> + HasObservers<Observers = OT>, E: Executor<EM, Z> + HasObservers<Observers = OT>,
EM: EventFirer<State = E::State>, EM: EventFirer<State = E::State>,
O: MapObserver, O: MapObserver,
C: AsRef<O>,
for<'de> <O as MapObserver>::Entry: Serialize + Deserialize<'de> + 'static, for<'de> <O as MapObserver>::Entry: Serialize + Deserialize<'de> + 'static,
OT: ObserversTuple<E::State>, OT: ObserversTuple<E::State>,
E::State: HasCorpus + HasMetadata + HasNamedMetadata + HasExecutions, E::State: HasCorpus + HasMetadata + HasNamedMetadata + HasExecutions,
@ -147,8 +148,9 @@ where
let map_first = &executor let map_first = &executor
.observers() .observers()
.match_name::<O>(&self.map_observer_name) .match_name::<C>(&self.map_observer_name)
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))? .ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
.as_ref()
.to_vec(); .to_vec();
let mut unstable_entries: Vec<usize> = vec![]; let mut unstable_entries: Vec<usize> = vec![];
@ -190,8 +192,9 @@ where
if self.track_stability { if self.track_stability {
let map = &executor let map = &executor
.observers() .observers()
.match_name::<O>(&self.map_observer_name) .match_name::<C>(&self.map_observer_name)
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))? .ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
.as_ref()
.to_vec(); .to_vec();
let history_map = &mut state let history_map = &mut state
@ -246,8 +249,9 @@ where
if state.has_metadata::<SchedulerMetadata>() { if state.has_metadata::<SchedulerMetadata>() {
let map = executor let map = executor
.observers() .observers()
.match_name::<O>(&self.map_observer_name) .match_name::<C>(&self.map_observer_name)
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?; .ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
.as_ref();
let mut bitmap_size = map.count_bytes(); let mut bitmap_size = map.count_bytes();
assert!(bitmap_size != 0); assert!(bitmap_size != 0);
@ -335,9 +339,10 @@ where
} }
} }
impl<O, OT, S> CalibrationStage<O, OT, S> impl<C, O, OT, S> CalibrationStage<C, O, OT, S>
where where
O: MapObserver, O: MapObserver,
C: AsRef<O>,
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
S: HasCorpus + HasMetadata + HasNamedMetadata, S: HasCorpus + HasMetadata + HasNamedMetadata,
{ {
@ -345,8 +350,9 @@ where
#[must_use] #[must_use]
pub fn new<F>(map_feedback: &F) -> Self pub fn new<F>(map_feedback: &F) -> Self
where where
F: HasObserverName + Named + UsesObserver<S, Observer = O>, F: HasObserverName + Named + UsesObserver<S, Observer = C>,
for<'it> O: AsIter<'it, Item = O::Entry>, for<'it> O: AsIter<'it, Item = O::Entry>,
C: AsRef<O>,
{ {
Self { Self {
map_observer_name: map_feedback.observer_name().to_string(), map_observer_name: map_feedback.observer_name().to_string(),
@ -362,8 +368,9 @@ where
#[must_use] #[must_use]
pub fn ignore_stability<F>(map_feedback: &F) -> Self pub fn ignore_stability<F>(map_feedback: &F) -> Self
where where
F: HasObserverName + Named + UsesObserver<S, Observer = O>, F: HasObserverName + Named + UsesObserver<S, Observer = C>,
for<'it> O: AsIter<'it, Item = O::Entry>, for<'it> O: AsIter<'it, Item = O::Entry>,
C: AsRef<O>,
{ {
Self { Self {
map_observer_name: map_feedback.observer_name().to_string(), map_observer_name: map_feedback.observer_name().to_string(),

View File

@ -54,20 +54,20 @@ impl Ord for Earlier {
/// The mutational stage using power schedules /// The mutational stage using power schedules
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct ColorizationStage<EM, O, E, Z> { pub struct ColorizationStage<C, E, EM, O, Z> {
map_observer_name: String, map_observer_name: String,
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
phantom: PhantomData<(E, EM, O, Z)>, phantom: PhantomData<(C, E, EM, O, E, Z)>,
} }
impl<EM, O, E, Z> UsesState for ColorizationStage<EM, O, E, Z> impl<C, E, EM, O, Z> UsesState for ColorizationStage<C, E, EM, O, Z>
where where
E: UsesState, E: UsesState,
{ {
type State = E::State; type State = E::State;
} }
impl<EM, O, E, Z> Named for ColorizationStage<EM, O, E, Z> impl<C, E, EM, O, Z> Named for ColorizationStage<C, E, EM, O, Z>
where where
E: UsesState, E: UsesState,
{ {
@ -76,13 +76,14 @@ where
} }
} }
impl<E, EM, O, Z> Stage<E, EM, Z> for ColorizationStage<EM, O, E, Z> impl<C, E, EM, O, Z> Stage<E, EM, Z> for ColorizationStage<C, E, EM, O, Z>
where where
EM: UsesState<State = E::State> + EventFirer, EM: UsesState<State = E::State> + EventFirer,
E: HasObservers + Executor<EM, Z>, E: HasObservers + Executor<EM, Z>,
E::State: HasCorpus + HasMetadata + HasRand + HasNamedMetadata, E::State: HasCorpus + HasMetadata + HasRand + HasNamedMetadata,
E::Input: HasBytesVec, E::Input: HasBytesVec,
O: MapObserver, O: MapObserver,
C: AsRef<O> + Named,
Z: UsesState<State = E::State>, Z: UsesState<State = E::State>,
{ {
#[inline] #[inline]
@ -150,10 +151,11 @@ impl TaintMetadata {
libafl_bolts::impl_serdeany!(TaintMetadata); libafl_bolts::impl_serdeany!(TaintMetadata);
impl<EM, O, E, Z> ColorizationStage<EM, O, E, Z> impl<C, E, EM, O, Z> ColorizationStage<C, E, EM, O, Z>
where where
EM: UsesState<State = E::State> + EventFirer, EM: UsesState<State = E::State> + EventFirer,
O: MapObserver, O: MapObserver,
C: AsRef<O> + Named,
E: HasObservers + Executor<EM, Z>, E: HasObservers + Executor<EM, Z>,
E::State: HasCorpus + HasMetadata + HasRand, E::State: HasCorpus + HasMetadata + HasRand,
E::Input: HasBytesVec, E::Input: HasBytesVec,
@ -297,9 +299,9 @@ where
#[must_use] #[must_use]
/// Creates a new [`ColorizationStage`] /// Creates a new [`ColorizationStage`]
pub fn new(map_observer_name: &O) -> Self { pub fn new(map_observer: &C) -> Self {
Self { Self {
map_observer_name: map_observer_name.name().to_string(), map_observer_name: map_observer.name().to_string(),
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -319,8 +321,9 @@ where
let observer = executor let observer = executor
.observers() .observers()
.match_name::<O>(name) .match_name::<C>(name)
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?; .ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
.as_ref();
let hash = observer.hash() as usize; let hash = observer.hash() as usize;

View File

@ -14,7 +14,8 @@ use crate::{
feedbacks::map::MapNoveltiesMetadata, feedbacks::map::MapNoveltiesMetadata,
inputs::{BytesInput, GeneralizedInputMetadata, GeneralizedItem, HasBytesVec, UsesInput}, inputs::{BytesInput, GeneralizedInputMetadata, GeneralizedItem, HasBytesVec, UsesInput},
mark_feature_time, mark_feature_time,
observers::{MapObserver, ObserversTuple}, observers::{CanTrack, MapObserver, ObserversTuple},
require_novelties_tracking,
stages::{RetryRestartHelper, Stage}, stages::{RetryRestartHelper, Stage},
start_timer, start_timer,
state::{HasCorpus, HasExecutions, UsesState}, state::{HasCorpus, HasExecutions, UsesState},
@ -41,19 +42,19 @@ fn find_next_char(list: &[Option<u8>], mut idx: usize, ch: u8) -> usize {
/// A stage that runs a tracer executor /// A stage that runs a tracer executor
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct GeneralizationStage<EM, O, OT, Z> { pub struct GeneralizationStage<C, EM, O, OT, Z> {
map_observer_name: String, map_observer_name: String,
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
phantom: PhantomData<(EM, O, OT, Z)>, phantom: PhantomData<(C, EM, O, OT, Z)>,
} }
impl<EM, O, OT, Z> Named for GeneralizationStage<EM, O, OT, Z> { impl<C, EM, O, OT, Z> Named for GeneralizationStage<C, EM, O, OT, Z> {
fn name(&self) -> &str { fn name(&self) -> &str {
"GeneralizationStage" "GeneralizationStage"
} }
} }
impl<EM, O, OT, Z> UsesState for GeneralizationStage<EM, O, OT, Z> impl<C, EM, O, OT, Z> UsesState for GeneralizationStage<C, EM, O, OT, Z>
where where
EM: UsesState, EM: UsesState,
EM::State: UsesInput<Input = BytesInput>, EM::State: UsesInput<Input = BytesInput>,
@ -61,9 +62,10 @@ where
type State = EM::State; type State = EM::State;
} }
impl<E, EM, O, Z> Stage<E, EM, Z> for GeneralizationStage<EM, O, E::Observers, Z> impl<C, E, EM, O, Z> Stage<E, EM, Z> for GeneralizationStage<C, EM, O, E::Observers, Z>
where where
O: MapObserver, O: MapObserver,
C: CanTrack + AsRef<O>,
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
E::Observers: ObserversTuple<E::State>, E::Observers: ObserversTuple<E::State>,
E::State: E::State:
@ -331,18 +333,20 @@ where
} }
} }
impl<EM, O, OT, Z> GeneralizationStage<EM, O, OT, Z> impl<C, EM, O, OT, Z> GeneralizationStage<C, EM, O, OT, Z>
where where
EM: UsesState, EM: UsesState,
O: MapObserver, O: MapObserver,
C: CanTrack + AsRef<O>,
OT: ObserversTuple<EM::State>, OT: ObserversTuple<EM::State>,
EM::State: UsesInput<Input = BytesInput> + HasExecutions + HasMetadata + HasCorpus, EM::State: UsesInput<Input = BytesInput> + HasExecutions + HasMetadata + HasCorpus,
{ {
/// Create a new [`GeneralizationStage`]. /// Create a new [`GeneralizationStage`].
#[must_use] #[must_use]
pub fn new(map_observer: &O) -> Self { pub fn new(map_observer: &C) -> Self {
require_novelties_tracking!("GeneralizationStage", C);
Self { Self {
map_observer_name: map_observer.name().to_string(), map_observer_name: map_observer.as_ref().name().to_string(),
phantom: PhantomData, phantom: PhantomData,
} }
} }
@ -387,8 +391,9 @@ where
let cnt = executor let cnt = executor
.observers() .observers()
.match_name::<O>(&self.map_observer_name) .match_name::<C>(&self.map_observer_name)
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))? .ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
.as_ref()
.how_many_set(novelties); .how_many_set(novelties);
Ok(cnt == novelties.len()) Ok(cnt == novelties.len())

View File

@ -239,7 +239,7 @@ impl SyncFromBrokerMetadata {
/// A stage that loads testcases from disk to sync with other fuzzers such as AFL++ /// A stage that loads testcases from disk to sync with other fuzzers such as AFL++
#[derive(Debug)] #[derive(Debug)]
pub struct SyncFromBrokerStage<IC, ICB, DI, S, SP> pub struct SyncFromBrokerStage<DI, IC, ICB, S, SP>
where where
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
S: UsesInput, S: UsesInput,
@ -247,10 +247,10 @@ where
ICB: InputConverter<From = DI, To = S::Input>, ICB: InputConverter<From = DI, To = S::Input>,
DI: Input, DI: Input,
{ {
client: LlmpEventConverter<IC, ICB, DI, S, SP>, client: LlmpEventConverter<DI, IC, ICB, S, SP>,
} }
impl<IC, ICB, DI, S, SP> UsesState for SyncFromBrokerStage<IC, ICB, DI, S, SP> impl<DI, IC, ICB, S, SP> UsesState for SyncFromBrokerStage<DI, IC, ICB, S, SP>
where where
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
S: State, S: State,
@ -261,7 +261,7 @@ where
type State = S; type State = S;
} }
impl<E, EM, IC, ICB, DI, S, SP, Z> Stage<E, EM, Z> for SyncFromBrokerStage<IC, ICB, DI, S, SP> impl<E, EM, IC, ICB, DI, S, SP, Z> Stage<E, EM, Z> for SyncFromBrokerStage<DI, IC, ICB, S, SP>
where where
EM: UsesState<State = S> + EventFirer, EM: UsesState<State = S> + EventFirer,
S: State + HasExecutions + HasCorpus + HasRand + HasMetadata + HasTestcase, S: State + HasExecutions + HasCorpus + HasRand + HasMetadata + HasTestcase,
@ -343,7 +343,7 @@ where
} }
} }
impl<IC, ICB, DI, S, SP> SyncFromBrokerStage<IC, ICB, DI, S, SP> impl<DI, IC, ICB, S, SP> SyncFromBrokerStage<DI, IC, ICB, S, SP>
where where
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
S: UsesInput, S: UsesInput,
@ -353,7 +353,7 @@ where
{ {
/// Creates a new [`SyncFromBrokerStage`] /// Creates a new [`SyncFromBrokerStage`]
#[must_use] #[must_use]
pub fn new(client: LlmpEventConverter<IC, ICB, DI, S, SP>) -> Self { pub fn new(client: LlmpEventConverter<DI, IC, ICB, S, SP>) -> Self {
Self { client } Self { client }
} }
} }

View File

@ -28,7 +28,7 @@ For bugs, feel free to open issues or contact us directly. Thank you for your su
Even though we will gladly assist you in finishing up your PR, try to Even though we will gladly assist you in finishing up your PR, try to
- keep all the crates compiling with *stable* rust (hide the eventual non-stable code under [`cfg`s](https://github.com/AFLplusplus/LibAFL/blob/main/libafl/build.rs#L26)) - keep all the crates compiling with *stable* rust (hide the eventual non-stable code under [`cfg`s](https://github.com/AFLplusplus/LibAFL/blob/main/libafl/build.rs#L26))
- run `cargo fmt` on your code before pushing - run `cargo nightly fmt` on your code before pushing
- check the output of `cargo clippy --all` or `./clippy.sh` - check the output of `cargo clippy --all` or `./clippy.sh`
- run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code. - run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code.

View File

@ -189,9 +189,7 @@ where
match self._get(id, &self.mapping.enabled) { match self._get(id, &self.mapping.enabled) {
Ok(input) => Ok(input), Ok(input) => Ok(input),
Err(Error::KeyNotFound(..)) => return self._get(id, &self.mapping.disabled), Err(Error::KeyNotFound(..)) => return self._get(id, &self.mapping.disabled),
Err(e) => { Err(e) => Err(e),
Err(e)
}
} }
} }
fn current(&self) -> &Option<CorpusId> { fn current(&self) -> &Option<CorpusId> {

View File

@ -171,4 +171,4 @@ where
} }
} }
pub type ShrinkMapFeedback<O, S, T> = MinMapFeedback<MappedEdgeMapObserver<O, T>, S, usize>; pub type ShrinkMapFeedback<C, O, S, T> = MinMapFeedback<C, MappedEdgeMapObserver<O, T>, S, usize>;

View File

@ -168,7 +168,7 @@ macro_rules! fuzz_with {
I2SRandReplace, StdScheduledMutator, StringCategoryRandMutator, StringSubcategoryRandMutator, I2SRandReplace, StdScheduledMutator, StringCategoryRandMutator, StringSubcategoryRandMutator,
StringCategoryTokenReplaceMutator, StringSubcategoryTokenReplaceMutator, Tokens, tokens_mutations StringCategoryTokenReplaceMutator, StringSubcategoryTokenReplaceMutator, Tokens, tokens_mutations
}, },
observers::{stacktrace::BacktraceObserver, TimeObserver}, observers::{stacktrace::BacktraceObserver, TimeObserver, CanTrack},
schedulers::{ schedulers::{
IndexesLenTimeMinimizerScheduler, powersched::PowerSchedule, PowerQueueScheduler, IndexesLenTimeMinimizerScheduler, powersched::PowerSchedule, PowerQueueScheduler,
}, },
@ -198,7 +198,7 @@ macro_rules! fuzz_with {
let grimoire_metadata = should_use_grimoire(&mut state, &$options, &mutator_status)?; let grimoire_metadata = should_use_grimoire(&mut state, &$options, &mutator_status)?;
let grimoire = grimoire_metadata.should(); let grimoire = grimoire_metadata.should();
let edges_observer = edge_maker(); let edges_observer = edge_maker().track_indices().track_novelties();
let size_edges_observer = MappedEdgeMapObserver::new(edge_maker(), SizeValueObserver::default()); let size_edges_observer = MappedEdgeMapObserver::new(edge_maker(), SizeValueObserver::default());
let keep_observer = LibfuzzerKeepFeedback::new(); let keep_observer = LibfuzzerKeepFeedback::new();
@ -220,8 +220,8 @@ macro_rules! fuzz_with {
); );
// New maximization map feedback linked to the edges observer // New maximization map feedback linked to the edges observer
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, true); let map_feedback = MaxMapFeedback::new(&edges_observer);
let shrinking_map_feedback = ShrinkMapFeedback::tracking(&size_edges_observer, false, false); let shrinking_map_feedback = ShrinkMapFeedback::new(&size_edges_observer);
// Set up a generalization stage for grimoire // Set up a generalization stage for grimoire
let generalization = GeneralizationStage::new(&edges_observer); let generalization = GeneralizationStage::new(&edges_observer);
@ -412,7 +412,7 @@ macro_rules! fuzz_with {
let grimoire = IfStage::new(|_, _, _, _| Ok(grimoire.into()), (StdMutationalStage::transforming(grimoire_mutator), ())); let grimoire = IfStage::new(|_, _, _, _| Ok(grimoire.into()), (StdMutationalStage::transforming(grimoire_mutator), ()));
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(PowerQueueScheduler::new(&mut state, &edges_observer, PowerSchedule::FAST)); let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, PowerQueueScheduler::new(&mut state, &edges_observer, PowerSchedule::FAST));
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -105,7 +105,7 @@ pub fn merge(
let edges_observer = let edges_observer =
MappedEdgeMapObserver::new(edges_observer, SizeTimeValueObserver::new(time)); MappedEdgeMapObserver::new(edges_observer, SizeTimeValueObserver::new(time));
let map_feedback = MinMapFeedback::tracking(&edges_observer, false, true); let map_feedback = MinMapFeedback::new(&edges_observer);
// Create an OOM observer to monitor if an OOM has occurred // Create an OOM observer to monitor if an OOM has occurred
let oom_observer = OomObserver::new(options.rss_limit(), options.malloc_limit()); let oom_observer = OomObserver::new(options.rss_limit(), options.malloc_limit());

View File

@ -55,6 +55,18 @@ where
} }
} }
impl<M, O> AsRef<Self> for MappedEdgeMapObserver<M, O> {
fn as_ref(&self) -> &Self {
self
}
}
impl<M, O> AsMut<Self> for MappedEdgeMapObserver<M, O> {
fn as_mut(&mut self) -> &mut Self {
self
}
}
impl<M, O> HasLen for MappedEdgeMapObserver<M, O> impl<M, O> HasLen for MappedEdgeMapObserver<M, O>
where where
M: HasLen, M: HasLen,

View File

@ -15,7 +15,7 @@ use libafl::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
token_mutations::Tokens, token_mutations::Tokens,
}, },
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::StdMutationalStage, stages::StdMutationalStage,
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
@ -126,8 +126,10 @@ impl<'a> ForkserverBytesCoverageSugar<'a> {
std::env::set_var("AFL_MAP_SIZE", format!("{MAP_SIZE}")); std::env::set_var("AFL_MAP_SIZE", format!("{MAP_SIZE}"));
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
let edges_observer = let edges_observer = unsafe {
unsafe { HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_map)) }; HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_map))
.track_indices()
};
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -136,7 +138,7 @@ impl<'a> ForkserverBytesCoverageSugar<'a> {
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, false), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -164,7 +166,8 @@ impl<'a> ForkserverBytesCoverageSugar<'a> {
let mut tokens = Tokens::new(); let mut tokens = Tokens::new();
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler =
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -18,7 +18,7 @@ use libafl::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator}, scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
token_mutations::{I2SRandReplace, Tokens}, token_mutations::{I2SRandReplace, Tokens},
}, },
observers::{HitcountsMapObserver, TimeObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::{ShadowTracingStage, StdMutationalStage}, stages::{ShadowTracingStage, StdMutationalStage},
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
@ -143,7 +143,8 @@ where
_core_id| { _core_id| {
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
let edges_observer = let edges_observer =
HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }); HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") })
.track_indices();
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
@ -154,7 +155,7 @@ where
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, false), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -186,7 +187,8 @@ where
} }
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler =
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -21,7 +21,7 @@ use libafl::{
token_mutations::Tokens, token_mutations::Tokens,
I2SRandReplace, I2SRandReplace,
}, },
observers::{HitcountsMapObserver, TimeObserver, VariableMapObserver}, observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler}, schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::{ShadowTracingStage, StdMutationalStage}, stages::{ShadowTracingStage, StdMutationalStage},
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
@ -156,6 +156,7 @@ where
edges_map_mut_slice(), edges_map_mut_slice(),
addr_of_mut!(edges::MAX_EDGES_NUM), addr_of_mut!(edges::MAX_EDGES_NUM),
)) ))
.track_indices()
}; };
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
@ -168,7 +169,7 @@ where
// This one is composed by two Feedbacks in OR // This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!( let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state // New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::tracking(&edges_observer, true, false), MaxMapFeedback::new(&edges_observer),
// Time feedback, this one does not need a feedback state // Time feedback, this one does not need a feedback state
TimeFeedback::with_observer(&time_observer) TimeFeedback::with_observer(&time_observer)
); );
@ -200,7 +201,8 @@ where
} }
// A minimization+queue policy to get testcasess from the corpus // A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new()); let scheduler =
IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
// A fuzzer with feedbacks and a corpus scheduler // A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

@ -159,6 +159,18 @@ mod observers {
} }
} }
impl<const DIFFERENTIAL: bool> AsRef<Self> for CountersMultiMapObserver<DIFFERENTIAL> {
fn as_ref(&self) -> &Self {
self
}
}
impl<const DIFFERENTIAL: bool> AsMut<Self> for CountersMultiMapObserver<DIFFERENTIAL> {
fn as_mut(&mut self) -> &mut Self {
self
}
}
impl<const DIFFERENTIAL: bool> MapObserver for CountersMultiMapObserver<DIFFERENTIAL> { impl<const DIFFERENTIAL: bool> MapObserver for CountersMultiMapObserver<DIFFERENTIAL> {
type Entry = u8; type Entry = u8;

70
scripts/build_all_fuzzers.sh Executable file
View File

@ -0,0 +1,70 @@
#!/bin/bash
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
cd "$SCRIPT_DIR/.." || exit 1
# TODO: This should be rewritten in rust, a Makefile, or some platform-independent language
if [[ -z "${RUN_ON_CI}" ]]; then
fuzzers=$(find ./fuzzers -mindepth 1 -maxdepth 1 -type d)
backtrace_fuzzers=$(find ./fuzzers/backtrace_baby_fuzzers -mindepth 1 -maxdepth 1 -type d)
else
cargo build -p build_and_test_fuzzers
fuzzers=$(cargo run -p build_and_test_fuzzers -- "remotes/origin/main" "HEAD^")
backtrace_fuzzers=""
export PROFILE=dev
export PROFILE_DIR=debug
fi
fuzzers=$(echo "$fuzzers" | tr ' ' '\n')
backtrace_fuzzers=$(echo "$backtrace_fuzzers" | tr ' ' '\n')
libafl=$(pwd)
# build with a shared target dir for all fuzzers. this should speed up
# compilation a bit, and allows for easier artifact management (caching and
# cargo clean).
export CARGO_TARGET_DIR="$libafl/target"
mkdir -p "$CARGO_TARGET_DIR"
git submodule init && git submodule update
# override default profile settings for speed
# export RUSTFLAGS="-C prefer-dynamic"
for profile in DEV RELEASE; # loop for all profiles
do
export CARGO_PROFILE_"$profile"_OPT_LEVEL=z # optimize for size
# runs into shared target dir bug:
# [pid 351769] openat(AT_FDCWD, "LibAFL/target/release/deps/libc-dbff77a14da5d893.libc.5deb7d4a-cgu.0.rcgu.dwo", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
# error: failed to build archive: No such file or directory
# export CARGO_PROFILE_"$profile"_SPLIT_DEBUGINFO=unpacked # minimize debug info
# export CARGO_PROFILE_"$profile"_PANIC=abort
# export CARGO_PROFILE_"$profile"_INCREMENTAL=true
done
# shellcheck disable=SC2116
for fuzzer in $(echo "$fuzzers" "$backtrace_fuzzers");
do
# skip nyx test on non-linux platforms
if [[ $fuzzer == *"nyx_"* ]]; then
continue
fi
cd "$fuzzer" || exit 1
# Clippy checks
echo "[*] Checking fmt for $fuzzer"
cargo +nightly fmt --all || exit 1
if [ -e ./Makefile.toml ]; then
echo "[*] Building $fuzzer"
cargo make build || exit 1
echo "[+] Done building $fuzzer"
else
echo "[*] Building $fuzzer"
cargo build || exit 1
echo "[+] Done building $fuzzer"
fi
# no cleaning -- this is a local test, we want to cache here
cd "$libafl" || exit 1
echo ""
done