Skip to content

Commit

Permalink
Make LibAFL-fuzz build on MacOS (#2549)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
domenukk and R9295 authored Sep 24, 2024
1 parent 967449e commit 691fd1f
Show file tree
Hide file tree
Showing 12 changed files with 138 additions and 60 deletions.
4 changes: 4 additions & 0 deletions fuzzers/others/libafl-fuzz/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
test/out-cmplog
test/out-instr
test/output-cmplog/
test/output/
2 changes: 1 addition & 1 deletion fuzzers/others/libafl-fuzz/Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ FUZZER = '${CARGO_TARGET_DIR}/${PROFILE_DIR}/${FUZZER_NAME}'
LLVM_CONFIG = { value = "llvm-config-18", condition = { env_not_set = [
"LLVM_CONFIG",
] } }
AFL_VERSION = "598a3c6b5e24bd33e84b914e145810d39f88adf6"
AFL_VERSION = "8b35dd49be5f846e945f6d6a9414623d195a99cb"
AFL_DIR = { value = "${PROJECT_DIR}/AFLplusplus" }
AFL_CC_PATH = { value = "${AFL_DIR}/afl-clang-fast" }
CC = { value = "clang" }
Expand Down
2 changes: 2 additions & 0 deletions fuzzers/others/libafl-fuzz/rustfmt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
group_imports = "StdExternalCrate"
imports_granularity = "Crate"
10 changes: 5 additions & 5 deletions fuzzers/others/libafl-fuzz/src/afl_stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::{
fmt::Display,
fs::{File, OpenOptions},
io::{BufRead, BufReader, Write},
path::PathBuf,
path::{Path, PathBuf},
process,
};

Expand Down Expand Up @@ -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");
if path.exists() {
// check if it contains any data
Expand All @@ -458,10 +458,10 @@ where
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");
if !path.exists() {
OpenOptions::new().append(true).create(true).open(path)?;
_ = OpenOptions::new().append(true).create(true).open(path)?;
}
Ok(())
}
Expand All @@ -470,7 +470,7 @@ where
let tmp_file = self.fuzzer_dir.join(".fuzzer_stats_tmp");
let stats_file = self.fuzzer_dir.join("fuzzer_stats");
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)?;
Ok(())
}
Expand Down
16 changes: 10 additions & 6 deletions fuzzers/others/libafl-fuzz/src/corpus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{
borrow::Cow,
fs::File,
io::{self, BufRead, BufReader},
path::{Path, PathBuf},
path::Path,
};

use libafl::{
Expand Down Expand Up @@ -39,10 +39,12 @@ pub fn generate_base_filename(state: &mut LibaflFuzzState) -> String {
name
}

// The function needs to be compatible with CustomFilepathToTestcaseFeedback
#[allow(clippy::unnecessary_wraps)]
pub fn set_corpus_filepath(
state: &mut LibaflFuzzState,
testcase: &mut Testcase<BytesInput>,
_fuzzer_dir: &PathBuf,
_fuzzer_dir: &Path,
) -> Result<(), Error> {
let mut name = generate_base_filename(state);
if testcase.hit_feedbacks().contains(&Cow::Borrowed("edges")) {
Expand All @@ -53,10 +55,12 @@ pub fn set_corpus_filepath(
Ok(())
}

// The function needs to be compatible with CustomFilepathToTestcaseFeedback
#[allow(clippy::unnecessary_wraps)]
pub fn set_solution_filepath(
state: &mut LibaflFuzzState,
testcase: &mut Testcase<BytesInput>,
output_dir: &PathBuf,
output_dir: &Path,
) -> Result<(), Error> {
// sig:0SIGNAL
// TODO: verify if 0 time if objective found during seed loading
Expand Down Expand Up @@ -137,7 +141,7 @@ pub fn check_autoresume(fuzzer_dir: &Path, auto_resume: bool) -> Result<Flock<Fi
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() {
return Err(io::Error::new(
// TODO: change this to ErrorKind::NotADirectory
Expand All @@ -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> {
for entry in std::fs::read_dir(output_dir)?.filter_map(std::result::Result::ok) {
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();
if path.is_dir() && path.join("is_main_node").exists() {
std::fs::remove_file(path.join("is_main_node"))?;
Expand Down
5 changes: 2 additions & 3 deletions fuzzers/others/libafl-fuzz/src/env_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ pub fn parse_envs(opt: &mut Opt) -> Result<(), Error> {
opt.no_autodict = parse_bool(&res)?;
}
if let Ok(res) = std::env::var("AFL_MAP_SIZE") {
let map_size = res.parse()?;
validate_map_size(map_size)?;
let map_size = validate_map_size(res.parse()?)?;
opt.map_size = Some(map_size);
};
if let Ok(res) = std::env::var("AFL_IGNORE_TIMEOUT") {
Expand Down Expand Up @@ -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 mut target_env = HashMap::new();
for vars in env_regex.captures_iter(s) {
target_env.insert(
_ = target_env.insert(
vars.get(1)
.ok_or(Error::illegal_argument("invalid AFL_TARGET_ENV format"))?
.as_str()
Expand Down
22 changes: 14 additions & 8 deletions fuzzers/others/libafl-fuzz/src/executor.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{
fs::File,
os::{linux::fs::MetadataExt, unix::fs::PermissionsExt},
os::unix::fs::PermissionsExt,
path::{Path, PathBuf},
};

Expand Down Expand Up @@ -54,7 +54,7 @@ pub fn check_binary(opt: &mut Opt, shmem_env_var: &str) -> Result<(), Error> {
let metadata = bin_path.metadata()?;
// AFL++ does not follow symlinks, BUT we do.
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;
if !is_reg || !is_executable || bin_size < 4 {
return Err(Error::illegal_argument(format!(
Expand Down Expand Up @@ -84,14 +84,15 @@ pub fn check_binary(opt: &mut Opt, shmem_env_var: &str) -> Result<(), Error> {
}

// check if the binary is an ELF file
#[cfg(target_os = "linux")]
if mmap[0..4] != [0x7f, 0x45, 0x4c, 0x46] {
return Err(Error::illegal_argument(format!(
"Program '{}' is not an ELF binary",
bin_path.display()
)));
}

#[cfg(all(target_os = "macos", not(target_arch = "arm")))]
#[cfg(target_vendor = "apple")]
{
if (mmap[0] != 0xCF || mmap[1] != 0xFA || mmap[2] != 0xED)
&& (mmap[0] != 0xCA || mmap[1] != 0xFE || mmap[2] != 0xBA)
Expand Down Expand Up @@ -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> {
let is_library =
filename.contains('.') && filename.ends_with(".so") || filename.ends_with(".dylib");
let extension = Path::new(filename).extension();
let is_library = if let Some(extension) = extension {
extension.eq_ignore_ascii_case("so") || extension.eq_ignore_ascii_case("dylib")
} else {
false
};

#[allow(clippy::useless_conversion)] // u16 on MacOS, u32 on Linux
let permission = if is_library {
S_IRUSR // user can read
u32::from(S_IRUSR) // user can read
} else {
S_IXUSR // user can exec
u32::from(S_IXUSR) // user can exec
};

// First we check if it is present in AFL_PATH
Expand Down Expand Up @@ -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}")))
}

fn check_file_found(file: &PathBuf, perm: u32) -> bool {
fn check_file_found(file: &Path, perm: u32) -> bool {
if !file.exists() {
return false;
}
Expand Down
14 changes: 7 additions & 7 deletions fuzzers/others/libafl-fuzz/src/feedback/filepath.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{
borrow::Cow,
fmt::{Debug, Formatter},
marker::PhantomData,
path::PathBuf,
path::{Path, PathBuf},
};

use libafl::{
Expand All @@ -26,7 +26,7 @@ pub struct CustomFilepathToTestcaseFeedback<F, I, S>
where
I: Input,
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.
func: F,
Expand All @@ -39,7 +39,7 @@ impl<F, I, S> CustomFilepathToTestcaseFeedback<F, I, S>
where
I: Input,
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`].
pub fn new(func: F, out_dir: PathBuf) -> Self {
Expand All @@ -56,7 +56,7 @@ impl<F, I, S, T> FeedbackFactory<CustomFilepathToTestcaseFeedback<F, I, S>, T>
where
I: Input,
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> {
Self {
Expand All @@ -71,7 +71,7 @@ impl<F, I, S> Named for CustomFilepathToTestcaseFeedback<F, I, S>
where
I: Input,
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> {
static NAME: Cow<'static, str> = Cow::Borrowed("CustomFilepathToTestcaseFeedback");
Expand All @@ -83,7 +83,7 @@ impl<F, I, S> Debug for CustomFilepathToTestcaseFeedback<F, I, S>
where
I: Input,
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 {
f.debug_struct("CustomFilepathToTestcaseFeedback")
Expand All @@ -94,7 +94,7 @@ where
impl<F, I, S> Feedback<S> for CustomFilepathToTestcaseFeedback<F, I, S>
where
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,
{
#[allow(clippy::wrong_self_convention)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ where
if self.should_run() {
self.record.push_back(input.clone());
if self.record.len() == self.record_size {
self.record.pop_front();
drop(self.record.pop_front());
}
}
Ok(false)
Expand Down
2 changes: 1 addition & 1 deletion fuzzers/others/libafl-fuzz/src/feedback/seed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::Opt;
/// A wrapper feedback used to determine actions for initial seeds.
/// Handles `AFL_EXIT_ON_SEED_ISSUES`, `AFL_IGNORE_SEED_ISSUES` & default afl-fuzz behavior
/// then, essentially becomes benign
#[allow(clippy::module_name_repetitions)]
#[allow(clippy::module_name_repetitions, clippy::struct_excessive_bools)]
#[derive(Debug)]
pub struct SeedFeedback<A, S>
where
Expand Down
Loading

0 comments on commit 691fd1f

Please sign in to comment.