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:
parent
967449e3cb
commit
691fd1f8cb
4
fuzzers/others/libafl-fuzz/.gitignore
vendored
Normal file
4
fuzzers/others/libafl-fuzz/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
test/out-cmplog
|
||||||
|
test/out-instr
|
||||||
|
test/output-cmplog/
|
||||||
|
test/output/
|
@ -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" }
|
||||||
|
2
fuzzers/others/libafl-fuzz/rustfmt.toml
Normal file
2
fuzzers/others/libafl-fuzz/rustfmt.toml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
group_imports = "StdExternalCrate"
|
||||||
|
imports_granularity = "Crate"
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
@ -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"))?;
|
||||||
|
@ -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()
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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)]
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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> {
|
||||||
|
@ -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(),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user