diff --git a/fuzzers/forkserver/libafl-fuzz/Cargo.toml b/fuzzers/forkserver/libafl-fuzz/Cargo.toml index 84da232f54..66eaa7cf3a 100644 --- a/fuzzers/forkserver/libafl-fuzz/Cargo.toml +++ b/fuzzers/forkserver/libafl-fuzz/Cargo.toml @@ -36,3 +36,4 @@ libafl_nyx = { path = "../../../libafl_nyx" } [features] default = ["track_hit_feedbacks"] track_hit_feedbacks = ["libafl/track_hit_feedbacks"] +fuzzbench = [] diff --git a/fuzzers/forkserver/libafl-fuzz/Makefile.toml b/fuzzers/forkserver/libafl-fuzz/Makefile.toml index dadcfd781f..337166891c 100644 --- a/fuzzers/forkserver/libafl-fuzz/Makefile.toml +++ b/fuzzers/forkserver/libafl-fuzz/Makefile.toml @@ -65,6 +65,7 @@ script = "echo done" dependencies = [ "build_afl", "test_instr", + "test_instr_fuzzbench", "test_cmplog", "test_frida", "test_qemu", @@ -75,6 +76,10 @@ dependencies = [ script_runner = "@shell" script = "cargo build --profile ${PROFILE}" +[tasks.build_libafl_fuzz_fuzzbench] +script_runner = "@shell" +script = "cargo build --profile ${PROFILE} --features fuzzbench" + [tasks.test_instr] script_runner = "@shell" script = ''' @@ -108,6 +113,39 @@ test -d "./test/output/fuzzer_main/crashes" || { ''' dependencies = ["build_afl", "build_libafl_fuzz"] +[tasks.test_instr_fuzzbench] +script_runner = "@shell" +script = ''' +AFL_PATH=${AFL_DIR} ${AFL_CC_PATH} ./test/test-instr.c -o ./test/out-instr + +export LIBAFL_DEBUG_OUTPUT=1 +export AFL_CORES=0 +export AFL_STATS_INTERVAL=1 + +timeout 5 ${FUZZER} -i ./test/seeds -o ./test/output-fuzzbench ./test/out-instr || true +test -n "$( ls ./test/output-fuzzbench/fuzzer_main/queue/id:000002* 2>/dev/null )" || { + echo "No new corpus entries found" + exit 1 +} +test -n "$( ls ./test/output-fuzzbench/fuzzer_main/fuzzer_stats 2>/dev/null )" || { + echo "No fuzzer_stats file found" + exit 1 +} +test -n "$( ls ./test/output-fuzzbench/fuzzer_main/plot_data 2>/dev/null )" || { + echo "No plot_data found" + exit 1 +} +test -d "./test/output-fuzzbench/fuzzer_main/hangs" || { + echo "No hangs directory found" + exit 1 +} +test -d "./test/output-fuzzbench/fuzzer_main/crashes" || { + echo "No crashes directory found" + exit 1 +} +''' +dependencies = ["build_afl", "build_libafl_fuzz_fuzzbench"] + [tasks.test_cmplog] script_runner = "@shell" script = ''' diff --git a/fuzzers/forkserver/libafl-fuzz/src/corpus.rs b/fuzzers/forkserver/libafl-fuzz/src/corpus.rs index 031a3f361a..ccf7d7ba88 100644 --- a/fuzzers/forkserver/libafl-fuzz/src/corpus.rs +++ b/fuzzers/forkserver/libafl-fuzz/src/corpus.rs @@ -1,7 +1,8 @@ use std::{ borrow::Cow, fs::File, - io::{self, BufRead, BufReader}, + io, + io::{BufRead, BufReader}, path::Path, }; @@ -164,6 +165,7 @@ pub fn create_dir_if_not_exists(path: &Path) -> io::Result<()> { } } +#[cfg(not(feature = "fuzzbench"))] pub fn remove_main_node_file(output_dir: &Path) -> Result<(), Error> { for entry in std::fs::read_dir(output_dir)?.filter_map(Result::ok) { let path = entry.path(); diff --git a/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs b/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs index 517240ab8b..4c970df349 100644 --- a/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs +++ b/fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs @@ -7,12 +7,15 @@ use std::{ time::Duration, }; +#[cfg(feature = "fuzzbench")] +use libafl::events::SimpleEventManager; +#[cfg(not(feature = "fuzzbench"))] +use libafl::events::{CentralizedEventManager, LlmpRestartingEventManager}; +#[cfg(feature = "fuzzbench")] +use libafl::monitors::SimpleMonitor; use libafl::{ corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus}, - events::{ - CentralizedEventManager, EventManagerHooksTuple, LlmpRestartingEventManager, - ProgressReporter, - }, + events::ProgressReporter, executors::forkserver::{ForkserverExecutor, ForkserverExecutorBuilder}, feedback_and, feedback_or, feedback_or_fast, feedbacks::{ @@ -39,6 +42,8 @@ use libafl::{ }, Error, Fuzzer, HasFeedback, HasMetadata, SerdeAny, }; +#[cfg(not(feature = "fuzzbench"))] +use libafl_bolts::shmem::StdShMemProvider; use libafl_bolts::{ core_affinity::CoreId, current_nanos, current_time, @@ -70,23 +75,47 @@ use crate::{ pub type LibaflFuzzState = StdState, StdRand, OnDiskCorpus>; -pub fn run_client( - state: Option, - mut restarting_mgr: CentralizedEventManager< - LlmpRestartingEventManager<(), LibaflFuzzState, SP>, - EMH, - LibaflFuzzState, - SP, - >, - fuzzer_dir: &Path, - core_id: CoreId, - opt: &Opt, - is_main_node: bool, -) -> Result<(), Error> -where - EMH: EventManagerHooksTuple + Copy + Clone, - SP: ShMemProvider, -{ +#[cfg(not(feature = "fuzzbench"))] +type LibaflFuzzManager = CentralizedEventManager< + LlmpRestartingEventManager<(), LibaflFuzzState, StdShMemProvider>, + (), + LibaflFuzzState, + StdShMemProvider, +>; +#[cfg(feature = "fuzzbench")] +type LibaflFuzzManager = SimpleEventManager, LibaflFuzzState>; + +macro_rules! define_run_client { + ($state: ident, $mgr: ident, $fuzzer_dir: ident, $core_id: ident, $opt:ident, $is_main_node: ident, $body:block) => { + #[cfg(not(feature = "fuzzbench"))] + pub fn run_client( + $state: Option, + mut $mgr: LibaflFuzzManager, + $fuzzer_dir: &Path, + $core_id: CoreId, + $opt: &Opt, + $is_main_node: bool, + ) -> Result<(), Error> { + $body + } + #[cfg(feature = "fuzzbench")] + pub fn run_client( + $state: Option, + mut $mgr: LibaflFuzzManager, + $fuzzer_dir: &Path, + $core_id: CoreId, + $opt: &Opt, + $is_main_node: bool, + ) -> Result<(), Error> + where + F: FnMut(&str), + { + $body + } + }; +} + +define_run_client!(state, mgr, fuzzer_dir, core_id, opt, is_main_node, { // Create the shared memory map for comms with the forkserver let mut shmem_provider = UnixShMemProvider::new().unwrap(); let mut shmem = shmem_provider @@ -382,7 +411,7 @@ where .load_initial_inputs_multicore( &mut fuzzer, &mut executor, - &mut restarting_mgr, + &mut mgr, &[queue_dir], &core_id, opt.cores.as_ref().expect("invariant; should never occur"), @@ -496,7 +525,7 @@ where &mut stages, &mut executor, &mut state, - &mut restarting_mgr, + &mut mgr, )?; } else { // The order of the stages matter! @@ -515,12 +544,12 @@ where &mut stages, &mut executor, &mut state, - &mut restarting_mgr, + &mut mgr, )?; } Ok(()) // TODO: serialize state when exiting. -} +}); fn base_forkserver_builder<'a>( opt: &'a Opt, @@ -539,7 +568,7 @@ fn base_forkserver_builder<'a>( if let Some(target_env) = &opt.target_env { executor = executor.envs(target_env); } - if opt.frida_mode { + if opt.frida_mode || opt.unicorn_mode || opt.qemu_mode { executor = executor.kill_signal(nix::sys::signal::Signal::SIGKILL); } if let Some(kill_signal) = opt.kill_signal { diff --git a/fuzzers/forkserver/libafl-fuzz/src/main.rs b/fuzzers/forkserver/libafl-fuzz/src/main.rs index 53d8562192..0e37a5fe58 100644 --- a/fuzzers/forkserver/libafl-fuzz/src/main.rs +++ b/fuzzers/forkserver/libafl-fuzz/src/main.rs @@ -71,23 +71,27 @@ mod feedback; mod scheduler; mod stages; use clap::Parser; -use corpus::{check_autoresume, create_dir_if_not_exists, remove_main_node_file}; +#[cfg(not(feature = "fuzzbench"))] +use corpus::remove_main_node_file; +use corpus::{check_autoresume, create_dir_if_not_exists}; mod corpus; mod executor; mod fuzzer; mod hooks; use env_parser::parse_envs; use fuzzer::run_client; -use libafl::{ - events::{CentralizedLauncher, EventConfig}, - monitors::MultiMonitor, - schedulers::powersched::BaseSchedule, - Error, -}; -use libafl_bolts::{ - core_affinity::{CoreId, Cores}, - shmem::{ShMemProvider, StdShMemProvider}, -}; +#[cfg(feature = "fuzzbench")] +use libafl::events::SimpleEventManager; +#[cfg(not(feature = "fuzzbench"))] +use libafl::events::{CentralizedLauncher, EventConfig}; +#[cfg(not(feature = "fuzzbench"))] +use libafl::monitors::MultiMonitor; +#[cfg(feature = "fuzzbench")] +use libafl::monitors::SimpleMonitor; +use libafl::{schedulers::powersched::BaseSchedule, Error}; +use libafl_bolts::core_affinity::{CoreId, Cores}; +#[cfg(not(feature = "fuzzbench"))] +use libafl_bolts::shmem::{ShMemProvider, StdShMemProvider}; use nix::sys::signal::Signal; const AFL_DEFAULT_INPUT_LEN_MAX: usize = 1_048_576; @@ -107,10 +111,14 @@ fn main() { executor::check_binary(&mut opt, SHMEM_ENV_VAR).expect("binary to be valid"); // Create the shared memory map provider for LLMP + #[cfg(not(feature = "fuzzbench"))] let shmem_provider = StdShMemProvider::new().unwrap(); // Create our Monitor + #[cfg(not(feature = "fuzzbench"))] let monitor = MultiMonitor::new(|s| println!("{s}")); + #[cfg(feature = "fuzzbench")] + let monitor = SimpleMonitor::new(|s| println!("{}", s)); opt.auto_resume = if opt.auto_resume { true @@ -126,7 +134,8 @@ fn main() { // Currently, we will error if we don't find our assigned dir. // This will also not work if we use core 1-8 and then later, 16-24 // since fuzzer names are using core_ids - match CentralizedLauncher::builder() + #[cfg(not(feature = "fuzzbench"))] + let res = CentralizedLauncher::builder() .shmem_provider(shmem_provider) .configuration(EventConfig::from_name("default")) .monitor(monitor) @@ -149,8 +158,16 @@ fn main() { .cores(&opt.cores.clone().expect("invariant; should never occur")) .broker_port(opt.broker_port.unwrap_or(AFL_DEFAULT_BROKER_PORT)) .build() - .launch() - { + .launch(); + #[cfg(feature = "fuzzbench")] + let res = { + let fuzzer_dir = opt.output_dir.join("fuzzer_main"); + let _ = check_autoresume(&fuzzer_dir, opt.auto_resume).unwrap(); + let mgr = SimpleEventManager::new(monitor); + let res = run_client(None, mgr, &fuzzer_dir, CoreId(0), &opt, true); + res + }; + match res { Ok(()) => unreachable!(), Err(Error::ShuttingDown) => println!("Fuzzing stopped by user. Good bye."), Err(err) => panic!("Failed to run launcher: {err:?}"),