From db51f4a33f0969f250740b2d74dfa9898a1fd823 Mon Sep 17 00:00:00 2001 From: Michael Rodler Date: Thu, 27 Apr 2023 14:21:48 +0000 Subject: [PATCH 1/6] improve cargo fuzz compat and bump to newer libAFL version * bumped libAFL version, which breaks sancov 8bit inline counters for some reason. => feature-guarded 8bit inline counters and use pcguard instead. * use the same paths for corpus/crashes as cargo fuzz => this should allow mixing `cargo fuzz` and `cargo libafl`. * feature-guard the Tui away and instead use `env_logger` by default. --- cargo-libafl/Cargo.toml | 6 +- cargo-libafl/build.rs | 11 +- cargo-libafl/cargo-libafl-runtime/Cargo.toml | 12 +- cargo-libafl/cargo-libafl-runtime/runtime.rs | 205 ++++++++++++------- cargo-libafl/src/project.rs | 14 +- 5 files changed, 161 insertions(+), 87 deletions(-) diff --git a/cargo-libafl/Cargo.toml b/cargo-libafl/Cargo.toml index d5928dc..842adbd 100644 --- a/cargo-libafl/Cargo.toml +++ b/cargo-libafl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cargo-libafl" -version = "0.1.8" +version = "0.1.9" authors = ["Andrea Fioraldi "] license = "MIT OR Apache-2.0" description = "A `cargo` wrapper to fuzz Rust code with `LibAFL`" @@ -28,3 +28,7 @@ toml = "0.5.9" cargo-binutils = "0.3.6" rustc_version = "0.4" xdg = "2.4" + +[features] +sancov_8bit = [] +tui = [] diff --git a/cargo-libafl/build.rs b/cargo-libafl/build.rs index fe1119b..1c9961f 100644 --- a/cargo-libafl/build.rs +++ b/cargo-libafl/build.rs @@ -47,10 +47,15 @@ fn main() { fs::copy(rt_path.join("runtime.rs"), out_path.join("runtime.rs")) .expect("Couldn't copy runtime.rs"); - assert!(Command::new("cargo") - .current_dir(&out_path) + let mut cmd = Command::new("cargo"); + cmd.current_dir(&out_path) .env("CARGO_TARGET_DIR", out_path.join("rt")) - .arg("build") + .arg("build"); + #[cfg(feature = "sancov_8bit")] + cmd.arg("--features").arg("sancov_8bit"); + #[cfg(feature = "tui")] + cmd.arg("--features").arg("tui"); + assert!(cmd .arg(&format!("--manifest-path={}/Cargo.toml", out_dir)) .arg("--release") .status() diff --git a/cargo-libafl/cargo-libafl-runtime/Cargo.toml b/cargo-libafl/cargo-libafl-runtime/Cargo.toml index e719446..e3683e8 100644 --- a/cargo-libafl/cargo-libafl-runtime/Cargo.toml +++ b/cargo-libafl/cargo-libafl-runtime/Cargo.toml @@ -13,11 +13,15 @@ edition = "2021" [workspace] [dependencies] -libafl = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "7ed1ac9" } -libafl_targets = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "7ed1ac9", features = ["sancov_8bit", "sancov_cmplog"] } +libafl = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "8ff8ae41f1ed2956bb1e906c5c7bd0505ca110c0" } +libafl_targets = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "8ff8ae41f1ed2956bb1e906c5c7bd0505ca110c0", features = ["sancov_8bit", "sancov_pcguard", +"sancov_cmplog", "pointer_maps"] } + mimalloc = { version = "*", default-features = false } portpicker = "0.1.1" clap = { version = "4.0", features = ["derive"] } +env_logger = "0.10" +log = "*" [profile.release] lto = true @@ -28,3 +32,7 @@ debug = true [lib] crate-type = ["staticlib", "rlib"] path = "runtime.rs" + +[features] +sancov_8bit = [] +tui = [] diff --git a/cargo-libafl/cargo-libafl-runtime/runtime.rs b/cargo-libafl/cargo-libafl-runtime/runtime.rs index 92d7488..6d4345e 100644 --- a/cargo-libafl/cargo-libafl-runtime/runtime.rs +++ b/cargo-libafl/cargo-libafl-runtime/runtime.rs @@ -18,15 +18,14 @@ use libafl::{ tuples::{tuple_list, Merge}, AsSlice, }, - corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus}, + corpus::{self, CachedOnDiskCorpus, Corpus, OnDiskCorpus}, events::EventConfig, executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor}, feedback_and_fast, feedback_or, feedbacks::{CrashFeedback, MaxMapFeedback, NewHashFeedback, TimeFeedback}, fuzzer::{Fuzzer, StdFuzzer}, generators::RandBytesGenerator, - inputs::HasTargetBytes, - monitors::tui::TuiMonitor, + inputs::{BytesInput, HasTargetBytes}, mutators::{ grimoire::{ GrimoireExtensionMutator, GrimoireRandomDeleteMutator, @@ -36,20 +35,29 @@ use libafl::{ token_mutations::{I2SRandReplace, Tokens}, StdMOptMutator, }, - observers::{BacktraceObserver, HitcountsIterableMapObserver, MultiMapObserver, TimeObserver}, - prelude::{GeneralizedInput, GeneralizedInputBytesGenerator}, + observers::{BacktraceObserver, TimeObserver}, schedulers::{ powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, PowerQueueScheduler, }, stages::{ - calibrate::CalibrationStage, GeneralizationStage, SkippableStage, StdMutationalStage, + calibrate::CalibrationStage, logics::IfElseStage, GeneralizationStage, StdMutationalStage, StdPowerMutationalStage, TracingStage, }, state::{HasCorpus, HasMetadata, StdState}, Error, }; -use libafl_targets::{CmpLogObserver, CMPLOG_MAP, COUNTERS_MAPS}; +use libafl_targets::CmpLogObserver; + +#[cfg(feature = "sancov_8bit")] +use libafl::observers::{HitcountsIterableMapObserver, MultiMapObserver}; +#[cfg(feature = "sancov_8bit")] +use libafl_targets::COUNTERS_MAPS; + +#[cfg(not(feature = "sancov_8bit"))] +use libafl::observers::HitcountsMapObserver; +#[cfg(not(feature = "sancov_8bit"))] +use libafl_targets::coverage::std_edges_map_observer; #[cfg(any(target_os = "linux", target_vendor = "apple"))] use libafl_targets::autotokens; @@ -89,17 +97,17 @@ struct Opt { #[arg(short = 'a', long, help = "Specify a remote broker", name = "REMOTE")] remote_broker_addr: Option, - #[arg(short, long, help = "Set an initial corpus directory", name = "INPUT")] + #[arg(short, long, help = "Set seed inputs directory", name = "INPUT")] input: Vec, - #[arg( - short, - long, - help = "Set the output directory, default is ./out", - name = "OUTPUT", - default_value = "./out" - )] - output: PathBuf, + #[arg(short, long, help = "Set the corpus directory", name = "CORPUS")] + corpus: PathBuf, + + #[arg(short, long, help = "Set the crashes directory", name = "CRASHES")] + crashes: PathBuf, + + #[arg(short, long, help = "show stdout or redirect to /dev/null")] + show_stdout: bool, #[arg( value_parser = timeout_from_millis_str, @@ -130,7 +138,8 @@ struct Opt { short = 'g', long, help = "Use GRIMOIRE, a mutator for text-based inputs", - name = "GRIMOIRE" + name = "GRIMOIRE", + default_value_t = false )] grimoire: bool, } @@ -153,6 +162,8 @@ pub fn main() { rust_fuzzer_initialize(); } + env_logger::init(); + let workdir = env::current_dir().unwrap(); let opt = Opt::parse(); @@ -160,44 +171,66 @@ pub fn main() { let cores = opt.cores; let broker_port = opt.broker_port.unwrap_or_else(|| { let port = portpicker::pick_unused_port().expect("No ports free"); - println!("Picking the free port {}", port); + log::info!("Picking the free port {}", port); port }); let remote_broker_addr = opt.remote_broker_addr; - let input_dirs = opt.input; - let output_dir = opt.output; + let mut input_dirs = opt.input.clone(); + let corpus_dir = opt.corpus; + let crashes_dir = opt.crashes; let token_files = opt.tokens; let timeout_ms = opt.timeout; - // let cmplog_enabled = matches.is_present("cmplog"); - if fs::create_dir(&output_dir).is_err() { - println!("Out dir at {:?} already exists.", &output_dir); - if !output_dir.is_dir() { - eprintln!("Out dir at {:?} is not a valid directory!", &output_dir); - return; + for dir in &[&corpus_dir, &crashes_dir] { + if fs::create_dir(dir).is_err() { + log::warn!("Out dir at {:?} already exists.", dir); + if !dir.is_dir() { + log::error!("Required directory at {:?} is not a valid directory!", dir); + return; + } } } - let crashes_dir = output_dir.join("crashes"); - let corpus_dir = output_dir.join("corpus"); - - println!("Workdir: {:?}", workdir.to_string_lossy().to_string()); + log::info!( + "Workdir: {:?}, Corpus: {:?}, Crashes: {:?}", + workdir.to_string_lossy().to_string(), + corpus_dir, + crashes_dir + ); let shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory"); - let monitor = TuiMonitor::new(format!("cargo-libafl v{}", VERSION), !opt.disable_unicode); + #[cfg(feature = "tui")] + let monitor = { + use libafl::monitors::tui::{ui::TuiUI, TuiMonitor}; + let ui = TuiUI::with_version( + String::from("cargo-libafl"), + VERSION.to_string(), + !opt.disable_unicode, + ); + TuiMonitor::new(ui) + }; + #[cfg(not(feature = "tui"))] + let monitor = libafl::monitors::MultiMonitor::new(|s| log::info!("{}", s)); let mut run_client = |state: Option>, mut mgr, _core_id| { - // Create an observation channel using the coverage map - let edges = unsafe { &mut COUNTERS_MAPS }; - let edges_observer = - HitcountsIterableMapObserver::new(MultiMapObserver::new("edges", edges)); + log::debug!("running fuzzing client"); + // first create an observation channel using the coverage map + + #[cfg(feature = "sancov_8bit")] + let edges_observer = { + let edges = unsafe { &mut COUNTERS_MAPS }; + // TODO: is the call to edges.clone here the reason for breaking sancov_8bit? + HitcountsIterableMapObserver::new(MultiMapObserver::new("edges", edges.clone())) + }; + + #[cfg(not(feature = "sancov_8bit"))] + let edges_observer = HitcountsMapObserver::new(unsafe { std_edges_map_observer("edges") }); // Create an observation channel to keep track of the execution time let time_observer = TimeObserver::new("time"); // Create the Cmp observer - let cmplog = unsafe { &mut CMPLOG_MAP }; - let cmplog_observer = CmpLogObserver::new("cmplog", cmplog, true); + let cmplog_observer = CmpLogObserver::new("cmplog", true); // Create a stacktrace observer let backtrace_observer = BacktraceObserver::new( @@ -207,7 +240,7 @@ pub fn main() { ); // New maximization map feedback linked to the edges observer - let map_feedback = MaxMapFeedback::new_tracking(&edges_observer, true, false); + let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, true); let calibration = CalibrationStage::new(&map_feedback); @@ -216,7 +249,7 @@ pub fn main() { let mut feedback = feedback_or!( map_feedback, // Time feedback, this one does not need a feedback state - TimeFeedback::new_with_observer(&time_observer) + TimeFeedback::with_observer(&time_observer) ); // A feedback to choose if an input is a solution or not @@ -244,7 +277,7 @@ pub fn main() { }); // Read tokens - if state.metadata().get::().is_none() { + if !state.has_metadata::() { let mut toks = Tokens::default(); for tokenfile in &token_files { toks.add_from_file(tokenfile)?; @@ -271,6 +304,7 @@ pub fn main() { 5, )?; + let grimoire_enabled: bool = opt.grimoire.into(); let grimoire_mutator = StdScheduledMutator::with_max_stack_pow( tuple_list!( GrimoireExtensionMutator::new(), @@ -282,20 +316,28 @@ pub fn main() { ), 3, ); - let grimoire = StdMutationalStage::new(grimoire_mutator); - let skippable_grimoire = SkippableStage::new(grimoire, |_s| opt.grimoire.into()); + let grimoire = StdMutationalStage::transforming(grimoire_mutator); + let skippable_grimoire = IfElseStage::new( + |_, _, _, _, _| Ok(grimoire_enabled), + tuple_list!(grimoire), + tuple_list!(), + ); + // SkippableStage::new(grimoire, |_s| opt.grimoire.into()); - let power = StdPowerMutationalStage::new(mutator, &edges_observer); + let power = StdPowerMutationalStage::new(mutator); // A minimization+queue policy to get testcasess from the corpus - let scheduler = - IndexesLenTimeMinimizerScheduler::new(PowerQueueScheduler::new(PowerSchedule::FAST)); + let scheduler = IndexesLenTimeMinimizerScheduler::new(PowerQueueScheduler::new( + &mut state, + &edges_observer, + PowerSchedule::FAST, + )); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); // The wrapped harness function, calling out to the LLVM-style harness - let mut harness = |input: &GeneralizedInput| { + let mut harness = |input: &BytesInput| { let target = input.target_bytes(); let buf = target.as_slice(); unsafe { @@ -307,9 +349,11 @@ pub fn main() { let mut tracing_harness = harness; let generalization = GeneralizationStage::new(&edges_observer); - - let skippable_generalization = - SkippableStage::new(generalization, |_s| opt.grimoire.into()); + let skippable_generalization = IfElseStage::new( + |_, _, _, _, _| Ok(grimoire_enabled), + tuple_list!(generalization), + tuple_list!(), + ); // Create the executor for an in-process function with one observer for edge coverage and one for the execution time let mut executor = TimeoutExecutor::new( @@ -342,37 +386,36 @@ pub fn main() { skippable_grimoire ); + input_dirs.push(corpus_dir.clone()); + log::debug!("Loading initial inputs from {:?}", &input_dirs); + // Load from disk + state + .load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &input_dirs) + .unwrap_or_else(|_| panic!("Failed to load initial corpus at {:?}", &input_dirs)); + log::debug!("We imported {} inputs from disk.", state.corpus().count()); + // In case the corpus is empty (on first run), reset if state.corpus().count() < 1 { - if input_dirs.is_empty() { - // Generator of printable bytearrays of max size 32 - let mut generator = - GeneralizedInputBytesGenerator::from(RandBytesGenerator::new(32)); - - // Generate 8 initial inputs - state - .generate_initial_inputs( - &mut fuzzer, - &mut executor, - &mut generator, - &mut mgr, - 8, - ) - .expect("Failed to generate the initial corpus"); - println!( - "We imported {} inputs from the generator.", - state.corpus().count() - ); - } else { - println!("Loading from {:?}", &input_dirs); - // Load from disk - state - .load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &input_dirs) - .unwrap_or_else(|_| { - panic!("Failed to load initial corpus at {:?}", &input_dirs) - }); - println!("We imported {} inputs from disk.", state.corpus().count()); - } + let mut generator = RandBytesGenerator::new(32); + + // Generate 8 initial inputs + state + .generate_initial_inputs(&mut fuzzer, &mut executor, &mut generator, &mut mgr, 128) + .expect("Failed to generate the initial corpus"); + log::debug!( + "We imported {} inputs from the generator.", + state.corpus().count() + ); + } + + log::debug!( + "Starting fuzz loop with {} inputs in the corpus", + state.corpus().count() + ); + + if state.corpus().count() == 0 { + log::error!("Failed to load corpus and/or generate initial inputs."); + return Err(Error::ShuttingDown); } fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)?; @@ -387,7 +430,11 @@ pub fn main() { .cores(&cores) .broker_port(broker_port) .remote_broker_addr(remote_broker_addr) - .stdout_file(Some("/dev/null")) + .stdout_file(Some(if opt.show_stdout { + "/dev/stdout" + } else { + "/dev/null" + })) .build() .launch() { diff --git a/cargo-libafl/src/project.rs b/cargo-libafl/src/project.rs index 647cab0..c3dc9f9 100644 --- a/cargo-libafl/src/project.rs +++ b/cargo-libafl/src/project.rs @@ -163,11 +163,18 @@ impl FuzzProject { cmd.arg("-Z").arg("build-std"); } + #[cfg(feature = "sancov_8bit")] let mut rustflags: String = "-Cpasses=sancov-module \ -Cllvm-args=-sanitizer-coverage-level=4 \ -Cllvm-args=-sanitizer-coverage-inline-8bit-counters \ -Cllvm-args=-sanitizer-coverage-pc-table" .to_owned(); + #[cfg(not(feature = "sancov_8bit"))] + let mut rustflags: String = "-Cpasses=sancov-module \ + -Cllvm-args=-sanitizer-coverage-level=4 \ + -Cllvm-args=-sanitizer-coverage-trace-pc-guard \ + -Cllvm-args=-sanitizer-coverage-pc-table" + .to_owned(); // link the fuzzer runtime rustflags.push_str(" -L "); @@ -264,8 +271,11 @@ impl FuzzProject { cmd.arg("--target-dir").arg(target_dir); } - let artifact_arg = ffi::OsString::from(self.artifacts_for(fuzz_target)?); - cmd.arg("--").arg("--output").arg(artifact_arg); + cmd.arg("--") + .arg("--corpus") + .arg(self.corpus_for(fuzz_target)?) + .arg("--crashes") + .arg(self.artifacts_for(fuzz_target)?); Ok(cmd) } From 70f38a36ca638594896ee74a561f04ece119f7d9 Mon Sep 17 00:00:00 2001 From: Michael Rodler Date: Fri, 5 May 2023 09:35:58 +0200 Subject: [PATCH 2/6] changed default log level to info for env_logger --- cargo-libafl/cargo-libafl-runtime/runtime.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-libafl/cargo-libafl-runtime/runtime.rs b/cargo-libafl/cargo-libafl-runtime/runtime.rs index 6d4345e..8f22a6c 100644 --- a/cargo-libafl/cargo-libafl-runtime/runtime.rs +++ b/cargo-libafl/cargo-libafl-runtime/runtime.rs @@ -162,7 +162,7 @@ pub fn main() { rust_fuzzer_initialize(); } - env_logger::init(); + env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init(); let workdir = env::current_dir().unwrap(); From 53efc581d0afd905b28566c6d98e2a08eb5ceb00 Mon Sep 17 00:00:00 2001 From: Michael Rodler Date: Mon, 8 May 2023 13:32:20 +0000 Subject: [PATCH 3/6] bump libAFL again --- cargo-libafl/cargo-libafl-runtime/Cargo.toml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cargo-libafl/cargo-libafl-runtime/Cargo.toml b/cargo-libafl/cargo-libafl-runtime/Cargo.toml index e3683e8..488b659 100644 --- a/cargo-libafl/cargo-libafl-runtime/Cargo.toml +++ b/cargo-libafl/cargo-libafl-runtime/Cargo.toml @@ -13,9 +13,8 @@ edition = "2021" [workspace] [dependencies] -libafl = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "8ff8ae41f1ed2956bb1e906c5c7bd0505ca110c0" } -libafl_targets = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "8ff8ae41f1ed2956bb1e906c5c7bd0505ca110c0", features = ["sancov_8bit", "sancov_pcguard", -"sancov_cmplog", "pointer_maps"] } +libafl = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "721c02c" } +libafl_targets = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "721c02c", features = ["sancov_8bit", "sancov_pcguard", "sancov_cmplog", "pointer_maps"] } mimalloc = { version = "*", default-features = false } portpicker = "0.1.1" From ef22e56846c6cffece6c655081427de53586873d Mon Sep 17 00:00:00 2001 From: Michael Rodler Date: Fri, 12 May 2023 08:28:54 +0000 Subject: [PATCH 4/6] fixed and defaulted back to sancov 8bit instrumentation instead of cloning the `COUNTER_MAPS` Vec, it is now drained into a new Vec pass to the Observer --- cargo-libafl/Cargo.toml | 1 + cargo-libafl/build.rs | 1 + cargo-libafl/cargo-libafl-runtime/Cargo.toml | 1 + cargo-libafl/cargo-libafl-runtime/runtime.rs | 8 ++++---- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/cargo-libafl/Cargo.toml b/cargo-libafl/Cargo.toml index 842adbd..4620002 100644 --- a/cargo-libafl/Cargo.toml +++ b/cargo-libafl/Cargo.toml @@ -30,5 +30,6 @@ rustc_version = "0.4" xdg = "2.4" [features] +default = ["sancov_8bit"] sancov_8bit = [] tui = [] diff --git a/cargo-libafl/build.rs b/cargo-libafl/build.rs index 1c9961f..f675589 100644 --- a/cargo-libafl/build.rs +++ b/cargo-libafl/build.rs @@ -51,6 +51,7 @@ fn main() { cmd.current_dir(&out_path) .env("CARGO_TARGET_DIR", out_path.join("rt")) .arg("build"); + cmd.arg("--no-default-features"); #[cfg(feature = "sancov_8bit")] cmd.arg("--features").arg("sancov_8bit"); #[cfg(feature = "tui")] diff --git a/cargo-libafl/cargo-libafl-runtime/Cargo.toml b/cargo-libafl/cargo-libafl-runtime/Cargo.toml index 488b659..97d49c8 100644 --- a/cargo-libafl/cargo-libafl-runtime/Cargo.toml +++ b/cargo-libafl/cargo-libafl-runtime/Cargo.toml @@ -33,5 +33,6 @@ crate-type = ["staticlib", "rlib"] path = "runtime.rs" [features] +default = [ "sancov_8bit" ] sancov_8bit = [] tui = [] diff --git a/cargo-libafl/cargo-libafl-runtime/runtime.rs b/cargo-libafl/cargo-libafl-runtime/runtime.rs index 8f22a6c..8e23ab3 100644 --- a/cargo-libafl/cargo-libafl-runtime/runtime.rs +++ b/cargo-libafl/cargo-libafl-runtime/runtime.rs @@ -16,7 +16,7 @@ use libafl::{ rands::StdRand, shmem::{ShMemProvider, StdShMemProvider}, tuples::{tuple_list, Merge}, - AsSlice, + AsMutSlice, AsSlice, }, corpus::{self, CachedOnDiskCorpus, Corpus, OnDiskCorpus}, events::EventConfig, @@ -36,6 +36,7 @@ use libafl::{ StdMOptMutator, }, observers::{BacktraceObserver, TimeObserver}, + prelude::OwnedMutSlice, schedulers::{ powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, PowerQueueScheduler, }, @@ -218,9 +219,8 @@ pub fn main() { #[cfg(feature = "sancov_8bit")] let edges_observer = { - let edges = unsafe { &mut COUNTERS_MAPS }; - // TODO: is the call to edges.clone here the reason for breaking sancov_8bit? - HitcountsIterableMapObserver::new(MultiMapObserver::new("edges", edges.clone())) + let edges = unsafe { COUNTERS_MAPS.drain(0..).collect() }; + HitcountsIterableMapObserver::new(MultiMapObserver::new("edges", edges)) }; #[cfg(not(feature = "sancov_8bit"))] From 28f04fa4f71f5369fce3a0cf58779d73424d578d Mon Sep 17 00:00:00 2001 From: Michael Rodler Date: Tue, 16 May 2023 15:32:57 +0000 Subject: [PATCH 5/6] added a skippable minimization stage that is configurable via the CLI --- cargo-libafl/cargo-libafl-runtime/runtime.rs | 33 ++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/cargo-libafl/cargo-libafl-runtime/runtime.rs b/cargo-libafl/cargo-libafl-runtime/runtime.rs index 8e23ab3..ef5553d 100644 --- a/cargo-libafl/cargo-libafl-runtime/runtime.rs +++ b/cargo-libafl/cargo-libafl-runtime/runtime.rs @@ -41,8 +41,8 @@ use libafl::{ powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, PowerQueueScheduler, }, stages::{ - calibrate::CalibrationStage, logics::IfElseStage, GeneralizationStage, StdMutationalStage, - StdPowerMutationalStage, TracingStage, + calibrate::CalibrationStage, logics::IfElseStage, GeneralizationStage, MapEqualityFactory, + StdMutationalStage, StdPowerMutationalStage, StdTMinMutationalStage, TracingStage, }, state::{HasCorpus, HasMetadata, StdState}, Error, @@ -143,6 +143,22 @@ struct Opt { default_value_t = false )] grimoire: bool, + + #[arg( + short = 'm', + long, + help = "Enable \"tmin\" minimization stage.", + name = "MINIMIZE", + default_value_t = false + )] + minimize: bool, + + #[arg( + long, + help = "Number of runs for the minimization stage.", + default_value_t = 512 + )] + minimizer_runs: usize, } extern "C" { @@ -239,6 +255,8 @@ pub fn main() { libafl::observers::HarnessType::InProcess, ); + let map_eq_factory = MapEqualityFactory::with_observer(&edges_observer); + // New maximization map feedback linked to the edges observer let map_feedback = MaxMapFeedback::tracking(&edges_observer, true, true); @@ -355,6 +373,16 @@ pub fn main() { tuple_list!(), ); + let tmin_enabled: bool = opt.minimize.into(); + let minimizer_mutations = StdScheduledMutator::new(havoc_mutations()); + let minimizer = + StdTMinMutationalStage::new(minimizer_mutations, map_eq_factory, opt.minimizer_runs); + let skippable_minimizer = IfElseStage::new( + |_, _, _, _, _| Ok(tmin_enabled), + tuple_list!(minimizer), + tuple_list!(), + ); + // Create the executor for an in-process function with one observer for edge coverage and one for the execution time let mut executor = TimeoutExecutor::new( InProcessExecutor::new( @@ -383,6 +411,7 @@ pub fn main() { tracing, i2s, power, + skippable_minimizer, skippable_grimoire ); From e0b8b35cdc3378e15975187e5bae112568860592 Mon Sep 17 00:00:00 2001 From: Michael Rodler Date: Tue, 16 May 2023 15:34:34 +0000 Subject: [PATCH 6/6] bumped libAFL version again; some misc changes --- cargo-libafl/cargo-libafl-runtime/Cargo.toml | 14 ++++++++------ cargo-libafl/cargo-libafl-runtime/runtime.rs | 8 ++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/cargo-libafl/cargo-libafl-runtime/Cargo.toml b/cargo-libafl/cargo-libafl-runtime/Cargo.toml index 97d49c8..21e6d31 100644 --- a/cargo-libafl/cargo-libafl-runtime/Cargo.toml +++ b/cargo-libafl/cargo-libafl-runtime/Cargo.toml @@ -5,22 +5,24 @@ name = "cargo-libafl-runtime" # 13.3.7 is a dummy value for templating purposes, it will be replaced with the actual version by ../build.rs version = "13.3.7" authors = ["Andrea Fioraldi "] +edition = "2021" license = "MIT OR Apache-2.0" -description = "The runtime lib for cargo-libafl" repository = "https://github.com/AFLplusplus/cargo-libafl" -edition = "2021" +description = "The runtime lib for cargo-libafl" [workspace] [dependencies] -libafl = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "721c02c" } -libafl_targets = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "721c02c", features = ["sancov_8bit", "sancov_pcguard", "sancov_cmplog", "pointer_maps"] } +libafl = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "6d2284d" } +libafl_targets = { git = "https://github.com/AFLplusplus/LibAFL.git", rev = "6d2284d", features = ["sancov_8bit", "sancov_pcguard", "sancov_cmplog", "pointer_maps"] } +# libafl = "0.10" +# libafl_targets = { version = "0.10", features = ["sancov_8bit", "sancov_pcguard", "sancov_cmplog", "pointer_maps"] } -mimalloc = { version = "*", default-features = false } -portpicker = "0.1.1" clap = { version = "4.0", features = ["derive"] } env_logger = "0.10" log = "*" +mimalloc = { version = "*", default-features = false } +portpicker = "0.1.1" [profile.release] lto = true diff --git a/cargo-libafl/cargo-libafl-runtime/runtime.rs b/cargo-libafl/cargo-libafl-runtime/runtime.rs index ef5553d..7b06485 100644 --- a/cargo-libafl/cargo-libafl-runtime/runtime.rs +++ b/cargo-libafl/cargo-libafl-runtime/runtime.rs @@ -235,6 +235,14 @@ pub fn main() { #[cfg(feature = "sancov_8bit")] let edges_observer = { + // libAFL 0.10 + // let edges = unsafe { + // COUNTERS_MAPS + // .drain(0..) + // .map(|x| OwnedMutSlice::from_raw_parts_mut(x.as_mut_ptr(), x.len())) + // .collect() + // }; + // libAFL git let edges = unsafe { COUNTERS_MAPS.drain(0..).collect() }; HitcountsIterableMapObserver::new(MultiMapObserver::new("edges", edges)) };