Feature: libafl-fuzzfuzzbench (#2689)

* fuzzbench

* clippy

* fmt

* fix unicorn CI?
This commit is contained in:
Aarnav 2024-11-13 13:32:21 +01:00 committed by GitHub
parent 7938acc4ce
commit d334860148
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 128 additions and 41 deletions

View File

@ -36,3 +36,4 @@ libafl_nyx = { path = "../../../libafl_nyx" }
[features] [features]
default = ["track_hit_feedbacks"] default = ["track_hit_feedbacks"]
track_hit_feedbacks = ["libafl/track_hit_feedbacks"] track_hit_feedbacks = ["libafl/track_hit_feedbacks"]
fuzzbench = []

View File

@ -65,6 +65,7 @@ script = "echo done"
dependencies = [ dependencies = [
"build_afl", "build_afl",
"test_instr", "test_instr",
"test_instr_fuzzbench",
"test_cmplog", "test_cmplog",
"test_frida", "test_frida",
"test_qemu", "test_qemu",
@ -75,6 +76,10 @@ dependencies = [
script_runner = "@shell" script_runner = "@shell"
script = "cargo build --profile ${PROFILE}" script = "cargo build --profile ${PROFILE}"
[tasks.build_libafl_fuzz_fuzzbench]
script_runner = "@shell"
script = "cargo build --profile ${PROFILE} --features fuzzbench"
[tasks.test_instr] [tasks.test_instr]
script_runner = "@shell" script_runner = "@shell"
script = ''' script = '''
@ -108,6 +113,39 @@ test -d "./test/output/fuzzer_main/crashes" || {
''' '''
dependencies = ["build_afl", "build_libafl_fuzz"] 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] [tasks.test_cmplog]
script_runner = "@shell" script_runner = "@shell"
script = ''' script = '''

View File

@ -1,7 +1,8 @@
use std::{ use std::{
borrow::Cow, borrow::Cow,
fs::File, fs::File,
io::{self, BufRead, BufReader}, io,
io::{BufRead, BufReader},
path::Path, 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> { pub fn remove_main_node_file(output_dir: &Path) -> Result<(), Error> {
for entry in std::fs::read_dir(output_dir)?.filter_map(Result::ok) { for entry in std::fs::read_dir(output_dir)?.filter_map(Result::ok) {
let path = entry.path(); let path = entry.path();

View File

@ -7,12 +7,15 @@ use std::{
time::Duration, 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::{ use libafl::{
corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus}, corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus},
events::{ events::ProgressReporter,
CentralizedEventManager, EventManagerHooksTuple, LlmpRestartingEventManager,
ProgressReporter,
},
executors::forkserver::{ForkserverExecutor, ForkserverExecutorBuilder}, executors::forkserver::{ForkserverExecutor, ForkserverExecutorBuilder},
feedback_and, feedback_or, feedback_or_fast, feedback_and, feedback_or, feedback_or_fast,
feedbacks::{ feedbacks::{
@ -39,6 +42,8 @@ use libafl::{
}, },
Error, Fuzzer, HasFeedback, HasMetadata, SerdeAny, Error, Fuzzer, HasFeedback, HasMetadata, SerdeAny,
}; };
#[cfg(not(feature = "fuzzbench"))]
use libafl_bolts::shmem::StdShMemProvider;
use libafl_bolts::{ use libafl_bolts::{
core_affinity::CoreId, core_affinity::CoreId,
current_nanos, current_time, current_nanos, current_time,
@ -70,23 +75,47 @@ use crate::{
pub type LibaflFuzzState = pub type LibaflFuzzState =
StdState<BytesInput, CachedOnDiskCorpus<BytesInput>, StdRand, OnDiskCorpus<BytesInput>>; StdState<BytesInput, CachedOnDiskCorpus<BytesInput>, StdRand, OnDiskCorpus<BytesInput>>;
pub fn run_client<EMH, SP>( #[cfg(not(feature = "fuzzbench"))]
state: Option<LibaflFuzzState>, type LibaflFuzzManager = CentralizedEventManager<
mut restarting_mgr: CentralizedEventManager< LlmpRestartingEventManager<(), LibaflFuzzState, StdShMemProvider>,
LlmpRestartingEventManager<(), LibaflFuzzState, SP>, (),
EMH,
LibaflFuzzState, LibaflFuzzState,
SP, StdShMemProvider,
>, >;
fuzzer_dir: &Path, #[cfg(feature = "fuzzbench")]
core_id: CoreId, type LibaflFuzzManager<F> = SimpleEventManager<SimpleMonitor<F>, LibaflFuzzState>;
opt: &Opt,
is_main_node: bool, 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<LibaflFuzzState>,
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<F>(
$state: Option<LibaflFuzzState>,
mut $mgr: LibaflFuzzManager<F>,
$fuzzer_dir: &Path,
$core_id: CoreId,
$opt: &Opt,
$is_main_node: bool,
) -> Result<(), Error> ) -> Result<(), Error>
where where
EMH: EventManagerHooksTuple<LibaflFuzzState> + Copy + Clone, F: FnMut(&str),
SP: ShMemProvider,
{ {
$body
}
};
}
define_run_client!(state, mgr, fuzzer_dir, core_id, opt, is_main_node, {
// Create the shared memory map for comms with the forkserver // Create the shared memory map for comms with the forkserver
let mut shmem_provider = UnixShMemProvider::new().unwrap(); let mut shmem_provider = UnixShMemProvider::new().unwrap();
let mut shmem = shmem_provider let mut shmem = shmem_provider
@ -382,7 +411,7 @@ where
.load_initial_inputs_multicore( .load_initial_inputs_multicore(
&mut fuzzer, &mut fuzzer,
&mut executor, &mut executor,
&mut restarting_mgr, &mut mgr,
&[queue_dir], &[queue_dir],
&core_id, &core_id,
opt.cores.as_ref().expect("invariant; should never occur"), opt.cores.as_ref().expect("invariant; should never occur"),
@ -496,7 +525,7 @@ where
&mut stages, &mut stages,
&mut executor, &mut executor,
&mut state, &mut state,
&mut restarting_mgr, &mut mgr,
)?; )?;
} else { } else {
// The order of the stages matter! // The order of the stages matter!
@ -515,12 +544,12 @@ where
&mut stages, &mut stages,
&mut executor, &mut executor,
&mut state, &mut state,
&mut restarting_mgr, &mut mgr,
)?; )?;
} }
Ok(()) Ok(())
// TODO: serialize state when exiting. // TODO: serialize state when exiting.
} });
fn base_forkserver_builder<'a>( fn base_forkserver_builder<'a>(
opt: &'a Opt, opt: &'a Opt,
@ -539,7 +568,7 @@ fn base_forkserver_builder<'a>(
if let Some(target_env) = &opt.target_env { if let Some(target_env) = &opt.target_env {
executor = executor.envs(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); executor = executor.kill_signal(nix::sys::signal::Signal::SIGKILL);
} }
if let Some(kill_signal) = opt.kill_signal { if let Some(kill_signal) = opt.kill_signal {

View File

@ -71,23 +71,27 @@ mod feedback;
mod scheduler; mod scheduler;
mod stages; mod stages;
use clap::Parser; 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 corpus;
mod executor; mod executor;
mod fuzzer; mod fuzzer;
mod hooks; mod hooks;
use env_parser::parse_envs; use env_parser::parse_envs;
use fuzzer::run_client; use fuzzer::run_client;
use libafl::{ #[cfg(feature = "fuzzbench")]
events::{CentralizedLauncher, EventConfig}, use libafl::events::SimpleEventManager;
monitors::MultiMonitor, #[cfg(not(feature = "fuzzbench"))]
schedulers::powersched::BaseSchedule, use libafl::events::{CentralizedLauncher, EventConfig};
Error, #[cfg(not(feature = "fuzzbench"))]
}; use libafl::monitors::MultiMonitor;
use libafl_bolts::{ #[cfg(feature = "fuzzbench")]
core_affinity::{CoreId, Cores}, use libafl::monitors::SimpleMonitor;
shmem::{ShMemProvider, StdShMemProvider}, 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; use nix::sys::signal::Signal;
const AFL_DEFAULT_INPUT_LEN_MAX: usize = 1_048_576; 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"); executor::check_binary(&mut opt, SHMEM_ENV_VAR).expect("binary to be valid");
// Create the shared memory map provider for LLMP // Create the shared memory map provider for LLMP
#[cfg(not(feature = "fuzzbench"))]
let shmem_provider = StdShMemProvider::new().unwrap(); let shmem_provider = StdShMemProvider::new().unwrap();
// Create our Monitor // Create our Monitor
#[cfg(not(feature = "fuzzbench"))]
let monitor = MultiMonitor::new(|s| println!("{s}")); let monitor = MultiMonitor::new(|s| println!("{s}"));
#[cfg(feature = "fuzzbench")]
let monitor = SimpleMonitor::new(|s| println!("{}", s));
opt.auto_resume = if opt.auto_resume { opt.auto_resume = if opt.auto_resume {
true true
@ -126,7 +134,8 @@ fn main() {
// Currently, we will error if we don't find our assigned dir. // 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 // This will also not work if we use core 1-8 and then later, 16-24
// since fuzzer names are using core_ids // since fuzzer names are using core_ids
match CentralizedLauncher::builder() #[cfg(not(feature = "fuzzbench"))]
let res = CentralizedLauncher::builder()
.shmem_provider(shmem_provider) .shmem_provider(shmem_provider)
.configuration(EventConfig::from_name("default")) .configuration(EventConfig::from_name("default"))
.monitor(monitor) .monitor(monitor)
@ -149,8 +158,16 @@ fn main() {
.cores(&opt.cores.clone().expect("invariant; should never occur")) .cores(&opt.cores.clone().expect("invariant; should never occur"))
.broker_port(opt.broker_port.unwrap_or(AFL_DEFAULT_BROKER_PORT)) .broker_port(opt.broker_port.unwrap_or(AFL_DEFAULT_BROKER_PORT))
.build() .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!(), Ok(()) => unreachable!(),
Err(Error::ShuttingDown) => println!("Fuzzing stopped by user. Good bye."), Err(Error::ShuttingDown) => println!("Fuzzing stopped by user. Good bye."),
Err(err) => panic!("Failed to run launcher: {err:?}"), Err(err) => panic!("Failed to run launcher: {err:?}"),