Update ForkserverBytesCoverageSugar to use parse_afl_cmdline, latest features (#1343)

* update forkserversugar to use parse_afl_cmdline

* added tokens/persistent/deferred to forkserver sugar

* removed deferred option

* added build_dynamic_map call; removed generic const

* clippy

---------

Co-authored-by: Dominik Maier <domenukk@gmail.com>
This commit is contained in:
epi 2023-07-12 05:16:46 -05:00 committed by GitHub
parent 3e0e753e9f
commit 72e54ac2f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -24,7 +24,7 @@ use libafl::{
scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
token_mutations::Tokens,
},
observers::{ConstMapObserver, HitcountsMapObserver, TimeObserver},
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::StdMutationalStage,
state::{HasCorpus, HasMetadata, StdState},
@ -39,7 +39,7 @@ pub const DEFAULT_MAP_SIZE: usize = 65536;
/// Creates a Forkserver-based fuzzer.
#[derive(Debug, TypedBuilder)]
pub struct ForkserverBytesCoverageSugar<'a, const MAP_SIZE: usize> {
pub struct ForkserverBytesCoverageSugar<'a> {
/// Laucher configuration (default is random)
#[builder(default = None, setter(strip_option))]
configuration: Option<String>,
@ -80,10 +80,15 @@ pub struct ForkserverBytesCoverageSugar<'a, const MAP_SIZE: usize> {
}
#[allow(clippy::similar_names)]
impl<'a, const MAP_SIZE: usize> ForkserverBytesCoverageSugar<'a, MAP_SIZE> {
impl<'a> ForkserverBytesCoverageSugar<'a> {
/// Runs the fuzzer.
#[allow(clippy::too_many_lines, clippy::similar_names)]
pub fn run(&mut self) {
// a large initial map size that should be enough
// to house all potential coverage maps for our targets
// (we will eventually reduce the used size according to the actual map)
const MAP_SIZE: usize = 2_621_440;
let conf = match self.configuration.as_ref() {
Some(name) => EventConfig::from_name(name),
None => EventConfig::AlwaysUnique,
@ -121,13 +126,12 @@ impl<'a, const MAP_SIZE: usize> ForkserverBytesCoverageSugar<'a, MAP_SIZE> {
shmem.write_to_env("__AFL_SHM_ID").unwrap();
let shmem_map = shmem.as_mut_slice();
// To let know the AFL++ binary that we have a big map
std::env::set_var("AFL_MAP_SIZE", format!("{MAP_SIZE}"));
// Create an observation channel using the coverage map
let edges_observer = unsafe {
HitcountsMapObserver::new(ConstMapObserver::<_, MAP_SIZE>::from_mut_ptr(
"shared_mem",
shmem_map.as_mut_ptr(),
))
};
let edges_observer =
unsafe { HitcountsMapObserver::new(StdMapObserver::new("shared_mem", shmem_map)) };
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
@ -160,12 +164,8 @@ impl<'a, const MAP_SIZE: usize> ForkserverBytesCoverageSugar<'a, MAP_SIZE> {
.unwrap()
});
// Create a dictionary if not existing
if let Some(tokens_file) = &self.tokens_file {
if state.metadata_map().get::<Tokens>().is_none() {
state.add_metadata(Tokens::from_file(tokens_file)?);
}
}
// Create an empty set of tokens, first populated by the target program
let mut tokens = Tokens::new();
// A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(QueueScheduler::new());
@ -176,18 +176,34 @@ impl<'a, const MAP_SIZE: usize> ForkserverBytesCoverageSugar<'a, MAP_SIZE> {
let forkserver = if self.shmem_testcase {
ForkserverExecutorBuilder::new()
.program(self.program.clone())
.args(self.arguments)
.parse_afl_cmdline(self.arguments)
.is_persistent(true)
.autotokens(&mut tokens)
.coverage_map_size(MAP_SIZE)
.debug_child(self.debug_output)
.shmem_provider(&mut shmem_provider_client)
.build(tuple_list!(edges_observer, time_observer))
.build_dynamic_map(edges_observer, tuple_list!(time_observer))
} else {
ForkserverExecutorBuilder::new()
.program(self.program.clone())
.args(self.arguments)
.parse_afl_cmdline(self.arguments)
.is_persistent(true)
.autotokens(&mut tokens)
.coverage_map_size(MAP_SIZE)
.debug_child(self.debug_output)
.build(tuple_list!(edges_observer, time_observer))
.build_dynamic_map(edges_observer, tuple_list!(time_observer))
};
if let Some(tokens_file) = &self.tokens_file {
// if a token file is provided, load it into our set of tokens
tokens.add_from_file(tokens_file)?;
}
if !tokens.is_empty() {
// add any known tokens to the state
state.add_metadata(tokens);
}
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
let mut executor = TimeoutForkserverExecutor::new(
forkserver.expect("Failed to create the executor."),
@ -346,7 +362,7 @@ pub mod pybind {
/// Run the fuzzer
#[allow(clippy::needless_pass_by_value)]
pub fn run(&self, program: String, arguments: Vec<String>) {
forkserver::ForkserverBytesCoverageSugar::<{ forkserver::DEFAULT_MAP_SIZE }>::builder()
forkserver::ForkserverBytesCoverageSugar::builder()
.input_dirs(&self.input_dirs)
.output_dir(self.output_dir.clone())
.broker_port(self.broker_port)