Skip to content

Commit

Permalink
Feature: libafl-fuzzfuzzbench (AFLplusplus#2689)
Browse files Browse the repository at this point in the history
* fuzzbench

* clippy

* fmt

* fix unicorn CI?
  • Loading branch information
R9295 authored and riesentoaster committed Nov 21, 2024
1 parent e49c718 commit 20756b2
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 41 deletions.
1 change: 1 addition & 0 deletions fuzzers/forkserver/libafl-fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ libafl_nyx = { path = "../../../libafl_nyx" }
[features]
default = ["track_hit_feedbacks"]
track_hit_feedbacks = ["libafl/track_hit_feedbacks"]
fuzzbench = []
38 changes: 38 additions & 0 deletions fuzzers/forkserver/libafl-fuzz/Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ script = "echo done"
dependencies = [
"build_afl",
"test_instr",
"test_instr_fuzzbench",
"test_cmplog",
"test_frida",
"test_qemu",
Expand All @@ -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 = '''
Expand Down Expand Up @@ -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 = '''
Expand Down
4 changes: 3 additions & 1 deletion fuzzers/forkserver/libafl-fuzz/src/corpus.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::{
borrow::Cow,
fs::File,
io::{self, BufRead, BufReader},
io,
io::{BufRead, BufReader},
path::Path,
};

Expand Down Expand Up @@ -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();
Expand Down
81 changes: 55 additions & 26 deletions fuzzers/forkserver/libafl-fuzz/src/fuzzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand All @@ -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,
Expand Down Expand Up @@ -70,23 +75,47 @@ use crate::{
pub type LibaflFuzzState =
StdState<BytesInput, CachedOnDiskCorpus<BytesInput>, StdRand, OnDiskCorpus<BytesInput>>;

pub fn run_client<EMH, SP>(
state: Option<LibaflFuzzState>,
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<LibaflFuzzState> + Copy + Clone,
SP: ShMemProvider,
{
#[cfg(not(feature = "fuzzbench"))]
type LibaflFuzzManager = CentralizedEventManager<
LlmpRestartingEventManager<(), LibaflFuzzState, StdShMemProvider>,
(),
LibaflFuzzState,
StdShMemProvider,
>;
#[cfg(feature = "fuzzbench")]
type LibaflFuzzManager<F> = SimpleEventManager<SimpleMonitor<F>, 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<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>
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
Expand Down Expand Up @@ -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"),
Expand Down Expand Up @@ -496,7 +525,7 @@ where
&mut stages,
&mut executor,
&mut state,
&mut restarting_mgr,
&mut mgr,
)?;
} else {
// The order of the stages matter!
Expand All @@ -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,
Expand All @@ -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 {
Expand Down
45 changes: 31 additions & 14 deletions fuzzers/forkserver/libafl-fuzz/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{launcher::ClientDescription, CentralizedLauncher, EventConfig},
monitors::MultiMonitor,
schedulers::powersched::BaseSchedule,
Error,
};
use libafl_bolts::{
core_affinity::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;
Expand All @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -157,8 +166,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:?}"),
Expand Down

0 comments on commit 20756b2

Please sign in to comment.