Make LibAFL-fuzz build on MacOS (#2549)

* Make LibAFL-fuzz build on MacOS

* Works on MacOS

* Update AFL++

* libafl-fuzz: fix CI cmplog (#2548)

* undo

* clippy

* clippy

---------

Co-authored-by: Aarnav <aarnavbos@gmail.com>
This commit is contained in:
Dominik Maier 2024-09-24 03:25:20 +02:00 committed by GitHub
parent 967449e3cb
commit 691fd1f8cb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 140 additions and 62 deletions

4
fuzzers/others/libafl-fuzz/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
test/out-cmplog
test/out-instr
test/output-cmplog/
test/output/

View File

@ -12,7 +12,7 @@ FUZZER = '${CARGO_TARGET_DIR}/${PROFILE_DIR}/${FUZZER_NAME}'
LLVM_CONFIG = { value = "llvm-config-18", condition = { env_not_set = [ LLVM_CONFIG = { value = "llvm-config-18", condition = { env_not_set = [
"LLVM_CONFIG", "LLVM_CONFIG",
] } } ] } }
AFL_VERSION = "598a3c6b5e24bd33e84b914e145810d39f88adf6" AFL_VERSION = "8b35dd49be5f846e945f6d6a9414623d195a99cb"
AFL_DIR = { value = "${PROJECT_DIR}/AFLplusplus" } AFL_DIR = { value = "${PROJECT_DIR}/AFLplusplus" }
AFL_CC_PATH = { value = "${AFL_DIR}/afl-clang-fast" } AFL_CC_PATH = { value = "${AFL_DIR}/afl-clang-fast" }
CC = { value = "clang" } CC = { value = "clang" }

View File

@ -0,0 +1,2 @@
group_imports = "StdExternalCrate"
imports_granularity = "Crate"

View File

@ -4,7 +4,7 @@ use std::{
fmt::Display, fmt::Display,
fs::{File, OpenOptions}, fs::{File, OpenOptions},
io::{BufRead, BufReader, Write}, io::{BufRead, BufReader, Write},
path::PathBuf, path::{Path, PathBuf},
process, process,
}; };
@ -444,7 +444,7 @@ where
} }
} }
fn create_plot_data_file(fuzzer_dir: &PathBuf) -> Result<(), Error> { fn create_plot_data_file(fuzzer_dir: &Path) -> Result<(), Error> {
let path = fuzzer_dir.join("plot_data"); let path = fuzzer_dir.join("plot_data");
if path.exists() { if path.exists() {
// check if it contains any data // check if it contains any data
@ -458,10 +458,10 @@ where
Ok(()) Ok(())
} }
fn create_fuzzer_stats_file(fuzzer_dir: &PathBuf) -> Result<(), Error> { fn create_fuzzer_stats_file(fuzzer_dir: &Path) -> Result<(), Error> {
let path = fuzzer_dir.join("fuzzer_stats"); let path = fuzzer_dir.join("fuzzer_stats");
if !path.exists() { if !path.exists() {
OpenOptions::new().append(true).create(true).open(path)?; _ = OpenOptions::new().append(true).create(true).open(path)?;
} }
Ok(()) Ok(())
} }
@ -470,7 +470,7 @@ where
let tmp_file = self.fuzzer_dir.join(".fuzzer_stats_tmp"); let tmp_file = self.fuzzer_dir.join(".fuzzer_stats_tmp");
let stats_file = self.fuzzer_dir.join("fuzzer_stats"); let stats_file = self.fuzzer_dir.join("fuzzer_stats");
std::fs::write(&tmp_file, stats.to_string())?; std::fs::write(&tmp_file, stats.to_string())?;
std::fs::copy(&tmp_file, &stats_file)?; _ = std::fs::copy(&tmp_file, &stats_file)?;
std::fs::remove_file(tmp_file)?; std::fs::remove_file(tmp_file)?;
Ok(()) Ok(())
} }

View File

@ -2,7 +2,7 @@ use std::{
borrow::Cow, borrow::Cow,
fs::File, fs::File,
io::{self, BufRead, BufReader}, io::{self, BufRead, BufReader},
path::{Path, PathBuf}, path::Path,
}; };
use libafl::{ use libafl::{
@ -39,10 +39,12 @@ pub fn generate_base_filename(state: &mut LibaflFuzzState) -> String {
name name
} }
// The function needs to be compatible with CustomFilepathToTestcaseFeedback
#[allow(clippy::unnecessary_wraps)]
pub fn set_corpus_filepath( pub fn set_corpus_filepath(
state: &mut LibaflFuzzState, state: &mut LibaflFuzzState,
testcase: &mut Testcase<BytesInput>, testcase: &mut Testcase<BytesInput>,
_fuzzer_dir: &PathBuf, _fuzzer_dir: &Path,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut name = generate_base_filename(state); let mut name = generate_base_filename(state);
if testcase.hit_feedbacks().contains(&Cow::Borrowed("edges")) { if testcase.hit_feedbacks().contains(&Cow::Borrowed("edges")) {
@ -53,10 +55,12 @@ pub fn set_corpus_filepath(
Ok(()) Ok(())
} }
// The function needs to be compatible with CustomFilepathToTestcaseFeedback
#[allow(clippy::unnecessary_wraps)]
pub fn set_solution_filepath( pub fn set_solution_filepath(
state: &mut LibaflFuzzState, state: &mut LibaflFuzzState,
testcase: &mut Testcase<BytesInput>, testcase: &mut Testcase<BytesInput>,
output_dir: &PathBuf, output_dir: &Path,
) -> Result<(), Error> { ) -> Result<(), Error> {
// sig:0SIGNAL // sig:0SIGNAL
// TODO: verify if 0 time if objective found during seed loading // TODO: verify if 0 time if objective found during seed loading
@ -137,7 +141,7 @@ pub fn check_autoresume(fuzzer_dir: &Path, auto_resume: bool) -> Result<Flock<Fi
Ok(file) Ok(file)
} }
pub fn create_dir_if_not_exists(path: &PathBuf) -> std::io::Result<()> { pub fn create_dir_if_not_exists(path: &Path) -> io::Result<()> {
if path.is_file() { if path.is_file() {
return Err(io::Error::new( return Err(io::Error::new(
// TODO: change this to ErrorKind::NotADirectory // TODO: change this to ErrorKind::NotADirectory
@ -158,8 +162,8 @@ pub fn create_dir_if_not_exists(path: &PathBuf) -> std::io::Result<()> {
} }
} }
pub fn remove_main_node_file(output_dir: &PathBuf) -> Result<(), Error> { pub fn remove_main_node_file(output_dir: &Path) -> Result<(), Error> {
for entry in std::fs::read_dir(output_dir)?.filter_map(std::result::Result::ok) { for entry in std::fs::read_dir(output_dir)?.filter_map(Result::ok) {
let path = entry.path(); let path = entry.path();
if path.is_dir() && path.join("is_main_node").exists() { if path.is_dir() && path.join("is_main_node").exists() {
std::fs::remove_file(path.join("is_main_node"))?; std::fs::remove_file(path.join("is_main_node"))?;

View File

@ -38,8 +38,7 @@ pub fn parse_envs(opt: &mut Opt) -> Result<(), Error> {
opt.no_autodict = parse_bool(&res)?; opt.no_autodict = parse_bool(&res)?;
} }
if let Ok(res) = std::env::var("AFL_MAP_SIZE") { if let Ok(res) = std::env::var("AFL_MAP_SIZE") {
let map_size = res.parse()?; let map_size = validate_map_size(res.parse()?)?;
validate_map_size(map_size)?;
opt.map_size = Some(map_size); opt.map_size = Some(map_size);
}; };
if let Ok(res) = std::env::var("AFL_IGNORE_TIMEOUT") { if let Ok(res) = std::env::var("AFL_IGNORE_TIMEOUT") {
@ -131,7 +130,7 @@ fn parse_target_env(s: &str) -> Result<Option<HashMap<String, String>>, Error> {
let env_regex = regex::Regex::new(r"([^\s=]+)\s*=\s*([^\s]+)").unwrap(); let env_regex = regex::Regex::new(r"([^\s=]+)\s*=\s*([^\s]+)").unwrap();
let mut target_env = HashMap::new(); let mut target_env = HashMap::new();
for vars in env_regex.captures_iter(s) { for vars in env_regex.captures_iter(s) {
target_env.insert( _ = target_env.insert(
vars.get(1) vars.get(1)
.ok_or(Error::illegal_argument("invalid AFL_TARGET_ENV format"))? .ok_or(Error::illegal_argument("invalid AFL_TARGET_ENV format"))?
.as_str() .as_str()

View File

@ -1,6 +1,6 @@
use std::{ use std::{
fs::File, fs::File,
os::{linux::fs::MetadataExt, unix::fs::PermissionsExt}, os::unix::fs::PermissionsExt,
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
@ -54,7 +54,7 @@ pub fn check_binary(opt: &mut Opt, shmem_env_var: &str) -> Result<(), Error> {
let metadata = bin_path.metadata()?; let metadata = bin_path.metadata()?;
// AFL++ does not follow symlinks, BUT we do. // AFL++ does not follow symlinks, BUT we do.
let is_reg = bin_path.is_file(); let is_reg = bin_path.is_file();
let bin_size = metadata.st_size(); let bin_size = metadata.len();
let is_executable = metadata.permissions().mode() & 0o111 != 0; let is_executable = metadata.permissions().mode() & 0o111 != 0;
if !is_reg || !is_executable || bin_size < 4 { if !is_reg || !is_executable || bin_size < 4 {
return Err(Error::illegal_argument(format!( return Err(Error::illegal_argument(format!(
@ -84,6 +84,7 @@ pub fn check_binary(opt: &mut Opt, shmem_env_var: &str) -> Result<(), Error> {
} }
// check if the binary is an ELF file // check if the binary is an ELF file
#[cfg(target_os = "linux")]
if mmap[0..4] != [0x7f, 0x45, 0x4c, 0x46] { if mmap[0..4] != [0x7f, 0x45, 0x4c, 0x46] {
return Err(Error::illegal_argument(format!( return Err(Error::illegal_argument(format!(
"Program '{}' is not an ELF binary", "Program '{}' is not an ELF binary",
@ -91,7 +92,7 @@ pub fn check_binary(opt: &mut Opt, shmem_env_var: &str) -> Result<(), Error> {
))); )));
} }
#[cfg(all(target_os = "macos", not(target_arch = "arm")))] #[cfg(target_vendor = "apple")]
{ {
if (mmap[0] != 0xCF || mmap[1] != 0xFA || mmap[2] != 0xED) if (mmap[0] != 0xCF || mmap[1] != 0xFA || mmap[2] != 0xED)
&& (mmap[0] != 0xCA || mmap[1] != 0xFE || mmap[2] != 0xBA) && (mmap[0] != 0xCA || mmap[1] != 0xFE || mmap[2] != 0xBA)
@ -186,13 +187,18 @@ fn find_executable_in_path<P: AsRef<Path>>(executable: &P) -> Option<PathBuf> {
} }
pub fn find_afl_binary(filename: &str, same_dir_as: Option<PathBuf>) -> Result<PathBuf, Error> { pub fn find_afl_binary(filename: &str, same_dir_as: Option<PathBuf>) -> Result<PathBuf, Error> {
let is_library = let extension = Path::new(filename).extension();
filename.contains('.') && filename.ends_with(".so") || filename.ends_with(".dylib"); let is_library = if let Some(extension) = extension {
extension.eq_ignore_ascii_case("so") || extension.eq_ignore_ascii_case("dylib")
let permission = if is_library {
S_IRUSR // user can read
} else { } else {
S_IXUSR // user can exec false
};
#[allow(clippy::useless_conversion)] // u16 on MacOS, u32 on Linux
let permission = if is_library {
u32::from(S_IRUSR) // user can read
} else {
u32::from(S_IXUSR) // user can exec
}; };
// First we check if it is present in AFL_PATH // First we check if it is present in AFL_PATH
@ -229,7 +235,7 @@ pub fn find_afl_binary(filename: &str, same_dir_as: Option<PathBuf>) -> Result<P
Err(Error::unknown(format!("cannot find {filename}"))) Err(Error::unknown(format!("cannot find {filename}")))
} }
fn check_file_found(file: &PathBuf, perm: u32) -> bool { fn check_file_found(file: &Path, perm: u32) -> bool {
if !file.exists() { if !file.exists() {
return false; return false;
} }

View File

@ -2,7 +2,7 @@ use std::{
borrow::Cow, borrow::Cow,
fmt::{Debug, Formatter}, fmt::{Debug, Formatter},
marker::PhantomData, marker::PhantomData,
path::PathBuf, path::{Path, PathBuf},
}; };
use libafl::{ use libafl::{
@ -26,7 +26,7 @@ pub struct CustomFilepathToTestcaseFeedback<F, I, S>
where where
I: Input, I: Input,
S: State<Input = I>, S: State<Input = I>,
F: FnMut(&mut S, &mut Testcase<I>, &PathBuf) -> Result<(), Error>, F: FnMut(&mut S, &mut Testcase<I>, &Path) -> Result<(), Error>,
{ {
/// Closure that returns the filename. /// Closure that returns the filename.
func: F, func: F,
@ -39,7 +39,7 @@ impl<F, I, S> CustomFilepathToTestcaseFeedback<F, I, S>
where where
I: Input, I: Input,
S: State<Input = I>, S: State<Input = I>,
F: FnMut(&mut S, &mut Testcase<I>, &PathBuf) -> Result<(), Error>, F: FnMut(&mut S, &mut Testcase<I>, &Path) -> Result<(), Error>,
{ {
/// Create a new [`CustomFilepathToTestcaseFeedback`]. /// Create a new [`CustomFilepathToTestcaseFeedback`].
pub fn new(func: F, out_dir: PathBuf) -> Self { pub fn new(func: F, out_dir: PathBuf) -> Self {
@ -56,7 +56,7 @@ impl<F, I, S, T> FeedbackFactory<CustomFilepathToTestcaseFeedback<F, I, S>, T>
where where
I: Input, I: Input,
S: State<Input = I>, S: State<Input = I>,
F: FnMut(&mut S, &mut Testcase<I>, &PathBuf) -> Result<(), Error> + Clone, F: FnMut(&mut S, &mut Testcase<I>, &Path) -> Result<(), Error> + Clone,
{ {
fn create_feedback(&self, _ctx: &T) -> CustomFilepathToTestcaseFeedback<F, I, S> { fn create_feedback(&self, _ctx: &T) -> CustomFilepathToTestcaseFeedback<F, I, S> {
Self { Self {
@ -71,7 +71,7 @@ impl<F, I, S> Named for CustomFilepathToTestcaseFeedback<F, I, S>
where where
I: Input, I: Input,
S: State<Input = I>, S: State<Input = I>,
F: FnMut(&mut S, &mut Testcase<I>, &PathBuf) -> Result<(), Error>, F: FnMut(&mut S, &mut Testcase<I>, &Path) -> Result<(), Error>,
{ {
fn name(&self) -> &Cow<'static, str> { fn name(&self) -> &Cow<'static, str> {
static NAME: Cow<'static, str> = Cow::Borrowed("CustomFilepathToTestcaseFeedback"); static NAME: Cow<'static, str> = Cow::Borrowed("CustomFilepathToTestcaseFeedback");
@ -83,7 +83,7 @@ impl<F, I, S> Debug for CustomFilepathToTestcaseFeedback<F, I, S>
where where
I: Input, I: Input,
S: State<Input = I>, S: State<Input = I>,
F: FnMut(&mut S, &mut Testcase<I>, &PathBuf) -> Result<(), Error>, F: FnMut(&mut S, &mut Testcase<I>, &Path) -> Result<(), Error>,
{ {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CustomFilepathToTestcaseFeedback") f.debug_struct("CustomFilepathToTestcaseFeedback")
@ -94,7 +94,7 @@ where
impl<F, I, S> Feedback<S> for CustomFilepathToTestcaseFeedback<F, I, S> impl<F, I, S> Feedback<S> for CustomFilepathToTestcaseFeedback<F, I, S>
where where
S: State<Input = I>, S: State<Input = I>,
F: FnMut(&mut S, &mut Testcase<S::Input>, &PathBuf) -> Result<(), Error>, F: FnMut(&mut S, &mut Testcase<S::Input>, &Path) -> Result<(), Error>,
I: Input, I: Input,
{ {
#[allow(clippy::wrong_self_convention)] #[allow(clippy::wrong_self_convention)]

View File

@ -102,7 +102,7 @@ where
if self.should_run() { if self.should_run() {
self.record.push_back(input.clone()); self.record.push_back(input.clone());
if self.record.len() == self.record_size { if self.record.len() == self.record_size {
self.record.pop_front(); drop(self.record.pop_front());
} }
} }
Ok(false) Ok(false)

View File

@ -11,7 +11,7 @@ use crate::Opt;
/// A wrapper feedback used to determine actions for initial seeds. /// A wrapper feedback used to determine actions for initial seeds.
/// Handles `AFL_EXIT_ON_SEED_ISSUES`, `AFL_IGNORE_SEED_ISSUES` & default afl-fuzz behavior /// Handles `AFL_EXIT_ON_SEED_ISSUES`, `AFL_IGNORE_SEED_ISSUES` & default afl-fuzz behavior
/// then, essentially becomes benign /// then, essentially becomes benign
#[allow(clippy::module_name_repetitions)] #[allow(clippy::module_name_repetitions, clippy::struct_excessive_bools)]
#[derive(Debug)] #[derive(Debug)]
pub struct SeedFeedback<A, S> pub struct SeedFeedback<A, S>
where where

View File

@ -1,4 +1,9 @@
use std::{borrow::Cow, marker::PhantomData, path::PathBuf, time::Duration}; use std::{
borrow::Cow,
marker::PhantomData,
path::{Path, PathBuf},
time::Duration,
};
use libafl::{ use libafl::{
corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus}, corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus},
@ -33,7 +38,7 @@ use libafl_bolts::{
fs::get_unique_std_input_file, fs::get_unique_std_input_file,
ownedref::OwnedRefMut, ownedref::OwnedRefMut,
rands::StdRand, rands::StdRand,
shmem::{ShMem, ShMemProvider, StdShMemProvider}, shmem::{ShMem, ShMemProvider, UnixShMemProvider},
tuples::{tuple_list, Handled, Merge}, tuples::{tuple_list, Handled, Merge},
AsSliceMut, AsSliceMut,
}; };
@ -66,7 +71,7 @@ pub fn run_client<EMH, SP>(
LibaflFuzzState, LibaflFuzzState,
SP, SP,
>, >,
fuzzer_dir: &PathBuf, fuzzer_dir: &Path,
core_id: CoreId, core_id: CoreId,
opt: &Opt, opt: &Opt,
is_main_node: bool, is_main_node: bool,
@ -76,7 +81,7 @@ where
SP: ShMemProvider, SP: ShMemProvider,
{ {
// Create the shared memory map for comms with the forkserver // Create the shared memory map for comms with the forkserver
let mut shmem_provider = StdShMemProvider::new().unwrap(); let mut shmem_provider = UnixShMemProvider::new().unwrap();
let mut shmem = shmem_provider let mut shmem = shmem_provider
.new_shmem(opt.map_size.unwrap_or(AFL_DEFAULT_MAP_SIZE)) .new_shmem(opt.map_size.unwrap_or(AFL_DEFAULT_MAP_SIZE))
.unwrap(); .unwrap();
@ -109,7 +114,7 @@ where
// Create a AFLStatsStage; // Create a AFLStatsStage;
let afl_stats_stage = AflStatsStage::new( let afl_stats_stage = AflStatsStage::new(
opt, opt,
fuzzer_dir.clone(), fuzzer_dir.to_path_buf(),
&edges_observer, &edges_observer,
user_token_count, user_token_count,
!opt.no_autodict, !opt.no_autodict,
@ -130,7 +135,7 @@ where
feedback_or!( feedback_or!(
map_feedback, map_feedback,
TimeFeedback::new(&time_observer), TimeFeedback::new(&time_observer),
CustomFilepathToTestcaseFeedback::new(set_corpus_filepath, fuzzer_dir.clone()) CustomFilepathToTestcaseFeedback::new(set_corpus_filepath, fuzzer_dir.to_path_buf())
), ),
opt, opt,
); );
@ -153,7 +158,7 @@ where
), ),
MaxMapFeedback::with_name("edges_objective", &edges_observer) MaxMapFeedback::with_name("edges_objective", &edges_observer)
), ),
CustomFilepathToTestcaseFeedback::new(set_solution_filepath, fuzzer_dir.clone()), CustomFilepathToTestcaseFeedback::new(set_solution_filepath, fuzzer_dir.to_path_buf()),
PersitentRecordFeedback::new(opt.persistent_record), PersitentRecordFeedback::new(opt.persistent_record),
); );
@ -163,7 +168,7 @@ where
StdRand::with_seed(opt.rng_seed.unwrap_or(current_nanos())), StdRand::with_seed(opt.rng_seed.unwrap_or(current_nanos())),
// TODO: configure testcache size // TODO: configure testcache size
CachedOnDiskCorpus::<BytesInput>::new(fuzzer_dir.join("queue"), 1000).unwrap(), CachedOnDiskCorpus::<BytesInput>::new(fuzzer_dir.join("queue"), 1000).unwrap(),
OnDiskCorpus::<BytesInput>::new(fuzzer_dir.clone()).unwrap(), OnDiskCorpus::<BytesInput>::new(fuzzer_dir).unwrap(),
&mut feedback, &mut feedback,
&mut objective, &mut objective,
) )
@ -234,19 +239,19 @@ where
} }
// Create the base Executor // Create the base Executor
let mut executor = base_executor(opt, &mut shmem_provider, fuzzer_dir)?; let mut executor_builder = base_executor_builder(opt, &mut shmem_provider, fuzzer_dir);
// Set a custom exit code to be interpreted as a Crash if configured. // Set a custom exit code to be interpreted as a Crash if configured.
if let Some(crash_exitcode) = opt.crash_exitcode { if let Some(crash_exitcode) = opt.crash_exitcode {
executor = executor.crash_exitcode(crash_exitcode); executor_builder = executor_builder.crash_exitcode(crash_exitcode);
} }
// Enable autodict if configured // Enable autodict if configured
if !opt.no_autodict { if !opt.no_autodict {
executor = executor.autotokens(&mut tokens); executor_builder = executor_builder.autotokens(&mut tokens);
}; };
// Finalize and build our Executor // Finalize and build our Executor
let mut executor = executor let mut executor = executor_builder
.build(tuple_list!(time_observer, edges_observer)) .build(tuple_list!(time_observer, edges_observer))
.unwrap(); .unwrap();
@ -270,7 +275,7 @@ where
)))? )))?
.to_string(); .to_string();
filename = format!("id:{id:0>6},time:0,execs:0,orig:{filename}"); filename = format!("id:{id:0>6},time:0,execs:0,orig:{filename}");
let cpy_res = std::fs::copy(&path, queue_dir.join(filename)); let cpy_res = std::fs::copy(path, queue_dir.join(filename));
match cpy_res { match cpy_res {
Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => { Err(e) if e.kind() == std::io::ErrorKind::InvalidInput => {
println!("skipping {} since it is not a regular file", path.display()); println!("skipping {} since it is not a regular file", path.display());
@ -354,7 +359,7 @@ where
// Create the CmpLog executor. // Create the CmpLog executor.
// Cmplog has 25% execution overhead so we give it double the timeout // Cmplog has 25% execution overhead so we give it double the timeout
let cmplog_executor = base_executor(opt, &mut shmem_provider, fuzzer_dir)? let cmplog_executor = base_executor_builder(opt, &mut shmem_provider, fuzzer_dir)
.timeout(Duration::from_millis(opt.hang_timeout * 2)) .timeout(Duration::from_millis(opt.hang_timeout * 2))
.program(cmplog_executable_path) .program(cmplog_executable_path)
.build(tuple_list!(cmplog_observer)) .build(tuple_list!(cmplog_observer))
@ -422,11 +427,11 @@ where
// TODO: serialize state when exiting. // TODO: serialize state when exiting.
} }
fn base_executor<'a>( fn base_executor_builder<'a>(
opt: &'a Opt, opt: &'a Opt,
shmem_provider: &'a mut StdShMemProvider, shmem_provider: &'a mut UnixShMemProvider,
fuzzer_dir: &PathBuf, fuzzer_dir: &Path,
) -> Result<ForkserverExecutorBuilder<'a, StdShMemProvider>, Error> { ) -> ForkserverExecutorBuilder<'a, UnixShMemProvider> {
let mut executor = ForkserverExecutor::builder() let mut executor = ForkserverExecutor::builder()
.program(opt.executable.clone()) .program(opt.executable.clone())
.coverage_map_size(opt.map_size.unwrap_or(AFL_DEFAULT_MAP_SIZE)) .coverage_map_size(opt.map_size.unwrap_or(AFL_DEFAULT_MAP_SIZE))
@ -469,7 +474,7 @@ fn base_executor<'a>(
.expect("to find afl-qemu-trace"), .expect("to find afl-qemu-trace"),
); );
} }
Ok(executor) executor
} }
pub fn fuzzer_target_mode(opt: &Opt) -> Cow<'static, str> { pub fn fuzzer_target_mode(opt: &Opt) -> Cow<'static, str> {

View File

@ -1,12 +1,69 @@
#![forbid(unexpected_cfgs)]
#![allow(incomplete_features)]
#![warn(clippy::cargo)]
#![allow(ambiguous_glob_reexports)]
#![deny(clippy::cargo_common_metadata)]
#![deny(rustdoc::broken_intra_doc_links)]
#![deny(clippy::all)]
#![deny(clippy::pedantic)] #![deny(clippy::pedantic)]
#![allow(clippy::unsafe_derive_deserialize)] #![allow(
#![allow(clippy::ptr_arg)] clippy::unreadable_literal,
#![allow(clippy::unnecessary_wraps)] clippy::type_repetition_in_bounds,
#![allow(clippy::module_name_repetitions)] clippy::missing_errors_doc,
#![allow(clippy::similar_names)] clippy::cast_possible_truncation,
#![allow(clippy::too_many_lines)] clippy::used_underscore_binding,
#![allow(clippy::struct_excessive_bools)] clippy::ptr_as_ptr,
#![allow(clippy::case_sensitive_file_extension_comparisons)] clippy::missing_panics_doc,
clippy::missing_docs_in_private_items,
clippy::module_name_repetitions,
clippy::ptr_cast_constness,
clippy::unsafe_derive_deserialize,
clippy::similar_names,
clippy::too_many_lines,
clippy::into_iter_without_iter, // broken
)]
#![cfg_attr(not(test), warn(
missing_debug_implementations,
//missing_docs,
trivial_casts,
trivial_numeric_casts,
unused_extern_crates,
unused_import_braces,
unused_qualifications,
//unused_results
))]
#![cfg_attr(
test,
deny(
missing_debug_implementations,
trivial_casts,
trivial_numeric_casts,
unused_extern_crates,
unused_import_braces,
unused_qualifications,
unused_must_use,
//unused_results
)
)]
#![cfg_attr(
test,
deny(
bad_style,
dead_code,
improper_ctypes,
non_shorthand_field_patterns,
no_mangle_generic_items,
overflowing_literals,
path_statements,
patterns_in_fns_without_body,
unconditional_recursion,
unused,
unused_allocation,
unused_comparisons,
unused_parens,
while_true
)
)]
use std::{collections::HashMap, path::PathBuf, time::Duration}; use std::{collections::HashMap, path::PathBuf, time::Duration};
mod afl_stats; mod afl_stats;
@ -256,7 +313,7 @@ struct Opt {
non_instrumented_mode: bool, non_instrumented_mode: bool,
} }
#[allow(dead_code)] #[allow(dead_code, clippy::struct_excessive_bools)]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct CmplogOpts { pub struct CmplogOpts {
file_size: CmplogFileSize, file_size: CmplogFileSize,
@ -285,6 +342,7 @@ impl From<&str> for CmplogFileSize {
} }
} }
#[allow(clippy::unnecessary_wraps)] // we need to be compatible with Clap's value_parser
fn parse_cmplog_args(s: &str) -> Result<CmplogOpts, String> { fn parse_cmplog_args(s: &str) -> Result<CmplogOpts, String> {
Ok(CmplogOpts { Ok(CmplogOpts {
file_size: s.into(), file_size: s.into(),