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
- keep all the crates compiling with *stable* rust (hide the eventual non-stable code under [`cfg`s](https://github.com/AFLplusplus/LibAFL/blob/main/libafl/build.rs#L26))
- run `cargo fmt` on your code before pushing
- run `cargo +nightly fmt` on your code before pushing
- check the output of `cargo clippy --all` or `./clippy.sh`
- run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -30,6 +30,7 @@ use libafl_bolts::{
use libafl_qemu::{
edges::{QemuEdgeCoverageChildHelper, EDGES_MAP_PTR, EDGES_MAP_SIZE},
elf::EasyElf,
emu::Emulator,
ArchExtras, CallingConvention, GuestAddr, GuestReg, MmapPerms, Qemu, QemuExitReason,
QemuExitReasonError, QemuForkExecutor, QemuHooks, QemuShutdownCause, Regs,
};
@ -63,10 +64,10 @@ impl From<Version> for Str {
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
#[command(
name = format!("qemu_cmin-{}",env!("CPU_TARGET")),
version = Version::default(),
about,
long_about = "Tool for generating minimizing corpus using QEMU instrumentation"
name = format ! ("qemu_cmin-{}", env ! ("CPU_TARGET")),
version = Version::default(),
about,
long_about = "Tool for generating minimizing corpus using QEMU instrumentation"
)]
pub struct FuzzerOptions {
#[arg(long, help = "Output directory")]
@ -171,7 +172,7 @@ pub fn fuzz() -> Result<(), Error> {
))
};
let mut feedback = MaxMapFeedback::tracking(&edges_observer, true, false);
let mut feedback = MaxMapFeedback::new(&edges_observer);
#[allow(clippy::let_unit_value)]
let mut objective = ();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -133,7 +133,7 @@ agpl = ["nautilus"]
nautilus = ["grammartec", "std", "serde_json/std"]
[build-dependencies]
reqwest = { version = "0.11", features = ["blocking"], optional = true}
reqwest = { version = "0.11", features = ["blocking"], optional = true }
rustversion = "1.0"
zip = { version = "0.6", optional = true }
@ -148,15 +148,15 @@ libafl_derive = { version = "0.11.2", path = "../libafl_derive", optional = true
rustversion = "1.0"
tuple_list = { version = "0.1.3" }
hashbrown = { version = "0.14", features = ["serde", "ahash"], default-features=false } # A faster hashmap, nostd compatible
hashbrown = { version = "0.14", features = ["serde", "ahash"], default-features = false } # A faster hashmap, nostd compatible
num-traits = { version = "0.2", default-features = false }
serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } # serialization lib
postcard = { version = "1.0", features = ["alloc"], default-features = false } # no_std compatible serde serialization format
bincode = {version = "1.3", optional = true }
bincode = { version = "1.3", optional = true }
c2rust-bitfields = { version = "0.18", features = ["no_std"] }
ahash = { version = "0.8", default-features=false } # The hash function already used in hashbrown
ahash = { version = "0.8", default-features = false } # The hash function already used in hashbrown
meminterval = { version = "0.4", features = ["serde"] }
backtrace = {version = "0.3", optional = true} # Used to get the stacktrace in StacktraceObserver
backtrace = { version = "0.3", optional = true } # Used to get the stacktrace in StacktraceObserver
typed-builder = { version = "0.16", optional = true } # Implement the builder pattern at compiletime
serde_json = { version = "1.0", optional = true, default-features = false, features = ["alloc"] }
@ -167,7 +167,7 @@ libm = "0.2.2"
ratatui = { version = "0.23.0", default-features = false, features = ['crossterm'], optional = true } # Commandline rendering, for TUI Monitor
crossterm = { version = "0.27.0", optional = true }
prometheus-client = { version= "0.21", optional = true} # For the prometheus monitor
prometheus-client = { version = "0.21", optional = true } # For the prometheus monitor
tide = { version = "0.16.0", optional = true }
async-std = { version = "1.12.0", features = ["attributes"], optional = true }
futures = { version = "0.3.24", optional = true }
@ -186,6 +186,9 @@ bitvec = { version = "1.0", optional = true, features = ["serde"] } # used for s
arrayvec = { version = "0.7.4", optional = true, default-features = false } # used for fixed-len collects
const_format = "0.2.32" # used for providing helpful compiler output
const_panic = "0.2.8" # similarly, for formatting const panic output
# optional-dev deps (change when target.'cfg(accessible(::std))'.test-dependencies will be stable)
serial_test = { version = "2", optional = true, default-features = false, features = ["logging"] }

View File

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

View File

@ -1499,7 +1499,7 @@ where
}
/// 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
S: UsesInput,
SP: ShMemProvider + 'static,
@ -1517,7 +1517,7 @@ where
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
SP: ShMemProvider + 'static,
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
S: UsesInput + HasExecutions + HasMetadata,
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
S: State,
SP: ShMemProvider,
@ -1745,7 +1745,7 @@ where
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
S: State,
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.
#[allow(clippy::pedantic)]
pub fn build_dynamic_map<MO, OT, S>(
pub fn build_dynamic_map<A, MO, OT, S>(
&mut self,
mut map_observer: MO,
mut map_observer: A,
other_observers: OT,
) -> Result<ForkserverExecutor<(MO, OT), S, SP>, Error>
) -> Result<ForkserverExecutor<(A, OT), S, SP>, Error>
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>,
S: UsesInput,
S::Input: Input + HasTargetBytes,
@ -660,10 +661,10 @@ impl<'a, SP> ForkserverExecutorBuilder<'a, SP> {
);
if let Some(dynamic_map_size) = self.map_size {
map_observer.truncate(dynamic_map_size);
map_observer.as_mut().truncate(dynamic_map_size);
}
let observers: (MO, OT) = other_observers.prepend(map_observer);
let observers = (map_observer, other_observers);
if self.uses_shmem_testcase && map.is_none() {
return Err(Error::illegal_state(

View File

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

View File

@ -80,10 +80,347 @@ fn hash_slice<T>(slice: &[T]) -> u64 {
hasher.finish()
}
/// Trait marker which indicates that this [`MapObserver`] is tracked for indices or novelties.
/// Implementors of feedbacks similar to [`crate::feedbacks::MapFeedback`] may wish to use this to
/// ensure that edge metadata is recorded as is appropriate for the provided observer.
///
/// If you get a type constraint failure for your map due to this type being unfulfilled, you must
/// call [`CanTrack::track_indices`] or [`CanTrack::track_novelties`] **at
/// the initialisation site of your map**.
///
/// This trait allows various components which interact with map metadata to ensure that the
/// information they need is actually recorded by the map feedback.
/// For example, if you are using [`crate::schedulers::MinimizerScheduler`]:
/// ```
/// # use libafl::corpus::InMemoryCorpus;
/// # use libafl::feedbacks::{Feedback, MapFeedbackMetadata};
/// use libafl::feedbacks::MaxMapFeedback;
/// # use libafl::inputs::BytesInput;
/// use libafl::observers::{StdMapObserver, CanTrack};
/// use libafl::schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler};
/// # use libafl::state::StdState;
/// # use libafl_bolts::serdeany::RegistryBuilder;
/// #
/// # #[cfg(any(not(feature = "serdeany_autoreg"), miri))]
/// # unsafe { MapFeedbackMetadata::<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
///
/// 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
pub trait MapObserver: HasLen + Named + Serialize + serde::de::DeserializeOwned
pub trait MapObserver:
HasLen + Named + Serialize + serde::de::DeserializeOwned + AsRef<Self> + AsMut<Self>
// where
// 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;
}
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`
#[derive(Debug)]
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>
where
T: Bounded
@ -455,6 +828,7 @@ where
self.map.as_slice()
}
}
impl<'a, T, const DIFFERENTIAL: bool> AsMutSlice for StdMapObserver<'a, T, DIFFERENTIAL>
where
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
@ -830,6 +1204,24 @@ where
}
}
impl<'a, T, const N: usize> AsRef<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>
where
T: Bounded
@ -922,6 +1314,7 @@ where
self.map.as_slice()
}
}
impl<'a, T, const N: usize> AsMutSlice for ConstMapObserver<'a, T, N>
where
T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug,
@ -1142,6 +1535,24 @@ where
}
}
impl<'a, T> AsRef<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>
where
T: Bounded
@ -1243,6 +1654,7 @@ where
&self.map.as_slice()[..cnt]
}
}
impl<'a, T> AsMutSlice for VariableMapObserver<'a, T>
where
T: 'static
@ -1305,8 +1717,8 @@ where
/// Map observer with AFL-like hitcounts postprocessing
///
/// [`MapObserver`]s that are not slice-backed,
/// such as [`MultiMapObserver`], can use [`HitcountsIterableMapObserver`] instead.
/// [`MapObserver`]s that are not slice-backed, such as [`MultiMapObserver`], can use
/// [`HitcountsIterableMapObserver`] instead.
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "M: serde::de::DeserializeOwned")]
pub struct HitcountsMapObserver<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>
where
M: MapObserver<Entry = u8>,
@ -1478,7 +1908,7 @@ where
impl<M> HitcountsMapObserver<M>
where
M: Serialize + serde::de::DeserializeOwned,
M: MapObserver,
{
/// Creates a new [`MapObserver`]
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>
where
M: MapObserver<Entry = u8>,
@ -1714,6 +2164,7 @@ where
self.base.as_slice()
}
}
impl<M> AsMutSlice for HitcountsIterableMapObserver<M>
where
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>
where
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>
where
T: 'static

View File

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

View File

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

View File

@ -6,6 +6,7 @@ use alloc::{
};
use core::{marker::PhantomData, time::Duration};
use libafl_bolts::Named;
use serde::{Deserialize, Serialize};
use crate::{
@ -170,24 +171,25 @@ pub enum PowerSchedule {
/// Note that this corpus is merely holding the metadata necessary for the power calculation
/// and here we DON'T actually calculate the power (we do it in the stage)
#[derive(Clone, Debug)]
pub struct PowerQueueScheduler<O, S> {
pub struct PowerQueueScheduler<C, O, S> {
strat: PowerSchedule,
map_observer_name: String,
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
S: State,
{
type State = S;
}
impl<O, S> RemovableScheduler for PowerQueueScheduler<O, S>
impl<C, O, S> RemovableScheduler for PowerQueueScheduler<C, O, S>
where
S: State + HasTestcase + HasMetadata + HasCorpus,
O: MapObserver,
C: AsRef<O>,
{
/// This will *NOT* neutralize the effect of this removed testcase from the global data such as `SchedulerMetadata`
fn on_remove(
@ -210,10 +212,11 @@ where
}
}
impl<O, S> AflScheduler<O, S> for PowerQueueScheduler<O, S>
impl<C, O, S> AflScheduler<C, O, S> for PowerQueueScheduler<C, O, S>
where
S: HasCorpus + HasMetadata + HasTestcase + State,
O: MapObserver,
C: AsRef<O>,
{
fn last_hash(&self) -> usize {
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
S: HasCorpus + HasMetadata + HasTestcase + State,
O: MapObserver,
C: AsRef<O>,
{
/// Called when a [`Testcase`] is added to the corpus
fn on_add(&mut self, state: &mut Self::State, idx: CorpusId) -> Result<(), Error> {
@ -287,14 +291,15 @@ where
}
}
impl<O, S> PowerQueueScheduler<O, S>
impl<C, O, S> PowerQueueScheduler<C, O, S>
where
S: HasMetadata,
O: MapObserver,
C: AsRef<O> + Named,
{
/// Create a new [`PowerQueueScheduler`]
#[must_use]
pub fn new(state: &mut S, map_observer: &O, strat: PowerSchedule) -> Self {
pub fn new(state: &mut S, map_observer: &C, strat: PowerSchedule) -> Self {
if !state.has_metadata::<SchedulerMetadata>() {
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.
use alloc::string::{String, ToString};
use core::marker::PhantomData;
use hashbrown::HashMap;
use libafl_bolts::rands::Rand;
use libafl_bolts::{rands::Rand, Named};
use serde::{Deserialize, Serialize};
use crate::{
@ -92,29 +92,30 @@ libafl_bolts::impl_serdeany!(WeightedScheduleMetadata);
/// A corpus scheduler using power schedules with weighted queue item selection algo.
#[derive(Clone, Debug)]
pub struct WeightedScheduler<F, O, S> {
pub struct WeightedScheduler<C, F, O, S> {
table_invalidated: bool,
strat: Option<PowerSchedule>,
map_observer_name: String,
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
F: TestcaseScore<S>,
O: MapObserver,
S: HasCorpus + HasMetadata + HasRand,
C: AsRef<O> + Named,
{
/// Create a new [`WeightedScheduler`] without any power schedule
#[must_use]
pub fn new(state: &mut S, map_observer: &O) -> Self {
pub fn new(state: &mut S, map_observer: &C) -> Self {
Self::with_schedule(state, map_observer, None)
}
/// Create a new [`WeightedScheduler`]
#[must_use]
pub fn with_schedule(state: &mut S, map_observer: &O, strat: Option<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(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
S: State,
{
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
F: TestcaseScore<S>,
O: MapObserver,
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`
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
F: TestcaseScore<S>,
S: HasCorpus + HasMetadata + HasTestcase + HasRand + State,
O: MapObserver,
S: HasCorpus + HasMetadata + HasTestcase + HasRand + State,
C: AsRef<O> + Named,
{
fn last_hash(&self) -> usize {
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
F: TestcaseScore<S>,
O: MapObserver,
S: HasCorpus + HasMetadata + HasRand + HasTestcase + State,
C: AsRef<O> + Named,
{
/// Called when a [`Testcase`] is added to the corpus
fn on_add(&mut self, state: &mut S, idx: CorpusId) -> Result<(), Error> {
@ -356,5 +360,5 @@ where
}
}
/// The standard corpus weight, same as aflpp
pub type StdWeightedScheduler<O, S> = WeightedScheduler<CorpusWeightTestcaseScore<S>, O, S>;
/// The standard corpus weight, same as in `AFL++`
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.
#[derive(Clone, Debug)]
pub struct CalibrationStage<O, OT, S> {
pub struct CalibrationStage<C, O, OT, S> {
map_observer_name: String,
map_name: String,
stage_max: usize,
/// If we should track stability
track_stability: bool,
restart_helper: ExecutionCountRestartHelper,
phantom: PhantomData<(O, OT, S)>,
phantom: PhantomData<(C, O, OT, S)>,
}
const CAL_STAGE_START: usize = 4; // AFL++'s CAL_CYCLES_FAST + 1
const CAL_STAGE_MAX: usize = 8; // AFL++'s CAL_CYCLES + 1
impl<O, OT, S> UsesState for CalibrationStage<O, OT, S>
impl<C, O, OT, S> UsesState for CalibrationStage<C, O, OT, S>
where
S: State,
{
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
E: Executor<EM, Z> + HasObservers<Observers = OT>,
EM: EventFirer<State = E::State>,
O: MapObserver,
C: AsRef<O>,
for<'de> <O as MapObserver>::Entry: Serialize + Deserialize<'de> + 'static,
OT: ObserversTuple<E::State>,
E::State: HasCorpus + HasMetadata + HasNamedMetadata + HasExecutions,
@ -147,8 +148,9 @@ where
let map_first = &executor
.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()))?
.as_ref()
.to_vec();
let mut unstable_entries: Vec<usize> = vec![];
@ -190,8 +192,9 @@ where
if self.track_stability {
let map = &executor
.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()))?
.as_ref()
.to_vec();
let history_map = &mut state
@ -246,8 +249,9 @@ where
if state.has_metadata::<SchedulerMetadata>() {
let map = executor
.observers()
.match_name::<O>(&self.map_observer_name)
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?;
.match_name::<C>(&self.map_observer_name)
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
.as_ref();
let mut bitmap_size = map.count_bytes();
assert!(bitmap_size != 0);
@ -335,9 +339,10 @@ where
}
}
impl<O, OT, S> CalibrationStage<O, OT, S>
impl<C, O, OT, S> CalibrationStage<C, O, OT, S>
where
O: MapObserver,
C: AsRef<O>,
OT: ObserversTuple<S>,
S: HasCorpus + HasMetadata + HasNamedMetadata,
{
@ -345,8 +350,9 @@ where
#[must_use]
pub fn new<F>(map_feedback: &F) -> Self
where
F: HasObserverName + Named + UsesObserver<S, Observer = O>,
F: HasObserverName + Named + UsesObserver<S, Observer = C>,
for<'it> O: AsIter<'it, Item = O::Entry>,
C: AsRef<O>,
{
Self {
map_observer_name: map_feedback.observer_name().to_string(),
@ -362,8 +368,9 @@ where
#[must_use]
pub fn ignore_stability<F>(map_feedback: &F) -> Self
where
F: HasObserverName + Named + UsesObserver<S, Observer = O>,
F: HasObserverName + Named + UsesObserver<S, Observer = C>,
for<'it> O: AsIter<'it, Item = O::Entry>,
C: AsRef<O>,
{
Self {
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
#[derive(Clone, Debug)]
pub struct ColorizationStage<EM, O, E, Z> {
pub struct ColorizationStage<C, E, EM, O, Z> {
map_observer_name: String,
#[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
E: UsesState,
{
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
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
EM: UsesState<State = E::State> + EventFirer,
E: HasObservers + Executor<EM, Z>,
E::State: HasCorpus + HasMetadata + HasRand + HasNamedMetadata,
E::Input: HasBytesVec,
O: MapObserver,
C: AsRef<O> + Named,
Z: UsesState<State = E::State>,
{
#[inline]
@ -150,10 +151,11 @@ impl 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
EM: UsesState<State = E::State> + EventFirer,
O: MapObserver,
C: AsRef<O> + Named,
E: HasObservers + Executor<EM, Z>,
E::State: HasCorpus + HasMetadata + HasRand,
E::Input: HasBytesVec,
@ -297,9 +299,9 @@ where
#[must_use]
/// Creates a new [`ColorizationStage`]
pub fn new(map_observer_name: &O) -> Self {
pub fn new(map_observer: &C) -> Self {
Self {
map_observer_name: map_observer_name.name().to_string(),
map_observer_name: map_observer.name().to_string(),
phantom: PhantomData,
}
}
@ -319,8 +321,9 @@ where
let observer = executor
.observers()
.match_name::<O>(name)
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?;
.match_name::<C>(name)
.ok_or_else(|| Error::key_not_found("MapObserver not found".to_string()))?
.as_ref();
let hash = observer.hash() as usize;

View File

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

View File

@ -239,7 +239,7 @@ impl SyncFromBrokerMetadata {
/// A stage that loads testcases from disk to sync with other fuzzers such as AFL++
#[derive(Debug)]
pub struct SyncFromBrokerStage<IC, ICB, DI, S, SP>
pub struct SyncFromBrokerStage<DI, IC, ICB, S, SP>
where
SP: ShMemProvider + 'static,
S: UsesInput,
@ -247,10 +247,10 @@ where
ICB: InputConverter<From = DI, To = S::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
SP: ShMemProvider + 'static,
S: State,
@ -261,7 +261,7 @@ where
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
EM: UsesState<State = S> + EventFirer,
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
SP: ShMemProvider + 'static,
S: UsesInput,
@ -353,7 +353,7 @@ where
{
/// Creates a new [`SyncFromBrokerStage`]
#[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 }
}
}

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
- keep all the crates compiling with *stable* rust (hide the eventual non-stable code under [`cfg`s](https://github.com/AFLplusplus/LibAFL/blob/main/libafl/build.rs#L26))
- run `cargo fmt` on your code before pushing
- run `cargo nightly fmt` on your code before pushing
- check the output of `cargo clippy --all` or `./clippy.sh`
- run `cargo build --no-default-features` to check for `no_std` compatibility (and possibly add `#[cfg(feature = "std")]`) to hide parts of your code.

View File

@ -189,9 +189,7 @@ where
match self._get(id, &self.mapping.enabled) {
Ok(input) => Ok(input),
Err(Error::KeyNotFound(..)) => return self._get(id, &self.mapping.disabled),
Err(e) => {
Err(e)
}
Err(e) => Err(e),
}
}
fn current(&self) -> &Option<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,
StringCategoryTokenReplaceMutator, StringSubcategoryTokenReplaceMutator, Tokens, tokens_mutations
},
observers::{stacktrace::BacktraceObserver, TimeObserver},
observers::{stacktrace::BacktraceObserver, TimeObserver, CanTrack},
schedulers::{
IndexesLenTimeMinimizerScheduler, powersched::PowerSchedule, PowerQueueScheduler,
},
@ -198,7 +198,7 @@ macro_rules! fuzz_with {
let grimoire_metadata = should_use_grimoire(&mut state, &$options, &mutator_status)?;
let grimoire = grimoire_metadata.should();
let edges_observer = edge_maker();
let edges_observer = edge_maker().track_indices().track_novelties();
let size_edges_observer = MappedEdgeMapObserver::new(edge_maker(), SizeValueObserver::default());
let keep_observer = LibfuzzerKeepFeedback::new();
@ -220,8 +220,8 @@ macro_rules! fuzz_with {
);
// New maximization map feedback linked to the edges observer
let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, true);
let shrinking_map_feedback = ShrinkMapFeedback::tracking(&size_edges_observer, false, false);
let map_feedback = MaxMapFeedback::new(&edges_observer);
let shrinking_map_feedback = ShrinkMapFeedback::new(&size_edges_observer);
// Set up a generalization stage for grimoire
let generalization = GeneralizationStage::new(&edges_observer);
@ -412,7 +412,7 @@ macro_rules! fuzz_with {
let grimoire = IfStage::new(|_, _, _, _| Ok(grimoire.into()), (StdMutationalStage::transforming(grimoire_mutator), ()));
// A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(PowerQueueScheduler::new(&mut state, &edges_observer, PowerSchedule::FAST));
let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, PowerQueueScheduler::new(&mut state, &edges_observer, PowerSchedule::FAST));
// A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);

View File

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

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>
where
M: HasLen,

View File

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

View File

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

View File

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

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> {
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