Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions fuzzers/forkserver/libafl-fuzz/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ Rewrite of afl-fuzz in Rust.
- [x] AFL_BENCH_JUST_ONE
- [x] AFL_DEBUG_CHILD
- [x] AFL_PERSISTENT
- [x] AFL_IGNORE_TIMEOUTS
- [x] AFL_IGNORE_TIMEOUTS (alias for AFL_IGNORE_TIMEOUT)
- [x] AFL_EXIT_ON_SEED_ISSUES
- [x] AFL_BENCH_UNTIL_CRASH
- [x] AFL_TMPDIR
- [x] AFL_CRASH_EXITCODE
- [x] AFL_TARGET_ENV
- [x] AFL_IGNORE_SEED_PROBLEMS (renamed to AFL_IGNORE_SEED_ISSUES)
- [x] AFL_IGNORE_SEED_PROBLEMS (alias for AFL_IGNORE_SEED_ISSUES)
- [x] AFL_CRASH_EXITCODE
- [x] AFL_INPUT_LEN_MIN
- [x] AFL_INPUT_LEN_MAX
Expand All @@ -30,12 +30,12 @@ Rewrite of afl-fuzz in Rust.
- [x] AFL_SYNC_TIME
- [x] AFL_AUTORESUME
- [x] AFL_PERSISTENT_RECORD
- [ ] AFL_FINAL_SYNC
- [ ] AFL_CRASHING_SEEDS_AS_NEW_CRASH
- [ ] AFL_IGNORE_UNKNOWN_ENVS
- [ ] AFL_NO_UI
- [ ] AFL_PIZZA_MODE :)
- [ ] AFL_EXIT_WHEN_DONE
- [x] AFL_FINAL_SYNC (accepted; currently no-op)
- [x] AFL_CRASHING_SEEDS_AS_NEW_CRASH (alias for AFL_CRASHING_SEED_AS_NEW_CRASH)
- [x] AFL_IGNORE_UNKNOWN_ENVS
- [x] AFL_NO_UI
- [x] AFL_PIZZA_MODE :)
- [x] AFL_EXIT_WHEN_DONE (accepted; currently no-op)
- [ ] AFL_EXIT_ON_TIME
- [ ] AFL_NO_AFFINITY
- [ ] AFL_FORKSERVER_KILL_SIGNAL
Expand All @@ -58,7 +58,7 @@ Rewrite of afl-fuzz in Rust.
- [ ] AFL_STATSD_HOST
- [ ] AFL_IMPORT
- [ ] AFL_SHUFFLE_QUEUE
- [ ] AFL_CUSTOM_QEMU_BIN
- [x] AFL_CUSTOM_QEMU_BIN (alias for AFL_QEMU_CUSTOM_BIN)
- [ ] AFL_PATH
- [ ] AFL_CUSTOM_MUTATOR_LIBRARY
- [ ] AFL_CUSTOM_MUTATOR_ONLY
Expand Down
94 changes: 87 additions & 7 deletions fuzzers/forkserver/libafl-fuzz/src/env_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,21 @@ use libafl_bolts::core_affinity::Cores;

use crate::Opt;

fn env_var_with_alias(canonical: &str, alias: &str) -> Option<String> {
std::env::var(canonical)
.ok()
.or_else(|| std::env::var(alias).ok())
}

pub fn parse_envs(opt: &mut Opt) -> Result<(), Error> {
if let Ok(res) = std::env::var("AFL_CORES") {
opt.cores = Some(Cores::from_cmdline(&res)?);
} else {
return Err(Error::illegal_argument("Missing AFL_CORES"));
}
if let Ok(res) = std::env::var("AFL_IGNORE_UNKNOWN_ENVS") {
opt.ignore_unknown_envs = parse_bool(&res)?;
}
if let Ok(res) = std::env::var("AFL_INPUT_LEN_MAX") {
opt.max_input_len = Some(res.parse()?);
}
Expand Down Expand Up @@ -44,7 +53,7 @@ pub fn parse_envs(opt: &mut Opt) -> Result<(), Error> {
let map_size = validate_map_size(res.parse()?)?;
opt.map_size = Some(map_size);
}
if let Ok(res) = std::env::var("AFL_IGNORE_TIMEOUT") {
if let Some(res) = env_var_with_alias("AFL_IGNORE_TIMEOUT", "AFL_IGNORE_TIMEOUTS") {
opt.ignore_timeouts = parse_bool(&res)?;
}
if let Ok(res) = std::env::var("AFL_TMPDIR") {
Expand Down Expand Up @@ -85,16 +94,19 @@ pub fn parse_envs(opt: &mut Opt) -> Result<(), Error> {
if let Ok(res) = std::env::var("AFL_EXIT_ON_SEED_ISSUES") {
opt.exit_on_seed_issues = parse_bool(&res)?;
}
if let Ok(res) = std::env::var("AFL_IGNORE_SEED_ISSUES") {
if let Some(res) = env_var_with_alias("AFL_IGNORE_SEED_ISSUES", "AFL_IGNORE_SEED_PROBLEMS") {
opt.ignore_seed_issues = parse_bool(&res)?;
}
if let Ok(res) = std::env::var("AFL_CRASHING_SEED_AS_NEW_CRASH") {
if let Some(res) = env_var_with_alias(
"AFL_CRASHING_SEED_AS_NEW_CRASH",
"AFL_CRASHING_SEEDS_AS_NEW_CRASH",
) {
opt.crash_seed_as_new_crash = parse_bool(&res)?;
}
if let Ok(res) = std::env::var("AFL_FRIDA_PERSISTENT_ADDR") {
opt.frida_persistent_addr = Some(res);
}
if let Ok(res) = std::env::var("AFL_QEMU_CUSTOM_BIN") {
if let Some(res) = env_var_with_alias("AFL_QEMU_CUSTOM_BIN", "AFL_CUSTOM_QEMU_BIN") {
opt.qemu_custom_bin = parse_bool(&res)?;
}
if let Ok(res) = std::env::var("AFL_CS_CUSTOM_BIN") {
Expand All @@ -103,9 +115,6 @@ pub fn parse_envs(opt: &mut Opt) -> Result<(), Error> {
if let Ok(res) = std::env::var("AFL_KILL_SIGNAL") {
opt.kill_signal = Some(res.parse()?);
}
if let Ok(res) = std::env::var("AFL_KILL_SIGNAL") {
opt.kill_signal = Some(res.parse()?);
}
if let Ok(res) = std::env::var("AFL_PERSISTENT_RECORD") {
opt.persistent_record = res.parse()?;
}
Expand All @@ -117,9 +126,80 @@ pub fn parse_envs(opt: &mut Opt) -> Result<(), Error> {
if let Ok(res) = std::env::var("AFL_USE_FASAN") {
opt.frida_asan = parse_bool(&res)?;
}
if let Ok(res) = std::env::var("AFL_NO_UI") {
opt.no_ui = parse_bool(&res)?;
}
if let Ok(res) = std::env::var("AFL_PIZZA_MODE") {
opt.pizza_mode = parse_bool(&res)?;
}
if let Ok(res) = std::env::var("AFL_EXIT_WHEN_DONE") {
opt.exit_when_done = parse_bool(&res)?;
}
if let Ok(res) = std::env::var("AFL_FINAL_SYNC") {
opt.final_sync = parse_bool(&res)?;
}
warn_on_unknown_afl_envs(opt.ignore_unknown_envs);
Ok(())
}

fn warn_on_unknown_afl_envs(ignore_unknown_envs: bool) {
const KNOWN_AFL_ENVS: &[&str] = &[
"AFL_AUTORESUME",
"AFL_BENCH_JUST_ONE",
"AFL_BENCH_UNTIL_CRASH",
"AFL_BROKER_PORT",
"AFL_CORES",
"AFL_CMPLOG_ONLY_NEW",
"AFL_CRASHING_SEED_AS_NEW_CRASH",
"AFL_CRASHING_SEEDS_AS_NEW_CRASH",
"AFL_CRASH_EXITCODE",
"AFL_CS_CUSTOM_BIN",
"AFL_CYCLE_SCHEDULES",
"AFL_CUSTOM_QEMU_BIN",
"AFL_DEBUG_CHILD",
"AFL_DEFER_FORKSRV",
"AFL_EXIT_ON_SEED_ISSUES",
"AFL_EXIT_WHEN_DONE",
"AFL_FINAL_SYNC",
"AFL_FRIDA_PERSISTENT_ADDR",
"AFL_FUZZER_STATS_UPDATE_INTERVAL",
"AFL_HANG_TMOUT",
"AFL_IGNORE_SEED_ISSUES",
"AFL_IGNORE_SEED_PROBLEMS",
"AFL_IGNORE_TIMEOUT",
"AFL_IGNORE_TIMEOUTS",
"AFL_IGNORE_UNKNOWN_ENVS",
"AFL_INPUT_LEN_MAX",
"AFL_INPUT_LEN_MIN",
"AFL_KILL_SIGNAL",
"AFL_MAP_SIZE",
"AFL_NO_AUTODICT",
"AFL_NO_UI",
"AFL_PERSISTENT",
"AFL_PERSISTENT_RECORD",
"AFL_PIZZA_MODE",
"AFL_PRELOAD",
"AFL_QEMU_CUSTOM_BIN",
"AFL_SKIP_BIN_CHECK",
"AFL_SYNC_TIME",
"AFL_TARGET_ENV",
"AFL_TMPDIR",
"AFL_USE_FASAN",
];

if ignore_unknown_envs {
return;
}

for (key, _) in std::env::vars() {
if key.starts_with("AFL_") && !KNOWN_AFL_ENVS.contains(&key.as_str()) {
eprintln!(
"warning: Unknown AFL environment variable '{key}'. Set AFL_IGNORE_UNKNOWN_ENVS=1 to suppress this warning."
);
}
}
}

fn parse_bool(val: &str) -> Result<bool, Error> {
match val {
"1" => Ok(true),
Expand Down
42 changes: 40 additions & 2 deletions fuzzers/forkserver/libafl-fuzz/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,32 @@ const DEFER_SIG: &str = "##SIG_AFL_DEFER_FORKSRV##\0";
const SHMEM_ENV_VAR: &str = "__AFL_SHM_ID";
static AFL_HARNESS_FILE_INPUT: &str = "@@";

fn print_line(s: &str) {
println!("{s}");
}

fn print_nop(_: &str) {}

fn main() {
env_logger::init();
let mut opt = Opt::parse();
parse_envs(&mut opt).expect("invalid configuration");

if opt.pizza_mode {
// TODO: Audit that the environment access only happens in single-threaded code
unsafe { std::env::set_var("AFL_PIZZA_MODE", "1") };
}
if opt.exit_when_done {
eprintln!(
"AFL_EXIT_WHEN_DONE is accepted but currently has no dedicated behavior in libafl-fuzz"
);
}
if opt.final_sync {
eprintln!(
"AFL_FINAL_SYNC is accepted but currently has no dedicated behavior in libafl-fuzz"
);
}

executor::check_binary(&mut opt, SHMEM_ENV_VAR).expect("binary to be valid");

// Create the shared memory map provider for LLMP
Expand All @@ -117,9 +139,15 @@ fn main() {

// Create our Monitor
#[cfg(not(feature = "fuzzbench"))]
let monitor = MultiMonitor::new(|s| println!("{s}"));
let monitor = {
let print_fn: fn(&str) = if opt.no_ui { print_nop } else { print_line };
MultiMonitor::new(print_fn)
};
#[cfg(feature = "fuzzbench")]
let monitor = SimpleMonitor::new(|s| println!("{}", s));
let monitor = {
let print_fn: fn(&str) = if opt.no_ui { print_nop } else { print_line };
SimpleMonitor::new(print_fn)
};

opt.auto_resume = if opt.auto_resume {
true
Expand Down Expand Up @@ -359,6 +387,16 @@ struct Opt {
crash_mode: bool,
#[clap(skip)]
non_instrumented_mode: bool,
#[clap(skip)]
final_sync: bool,
#[clap(skip)]
ignore_unknown_envs: bool,
#[clap(skip)]
no_ui: bool,
#[clap(skip)]
pizza_mode: bool,
#[clap(skip)]
exit_when_done: bool,
}

#[expect(dead_code, clippy::struct_excessive_bools)]
Expand Down
Loading