From 3ca906b7d33f99626523b23d8030ff2856fceaff Mon Sep 17 00:00:00 2001 From: Aarnav Date: Mon, 26 Aug 2024 19:30:38 +0200 Subject: [PATCH] Libafl-fuzz: fix unicorn mode (#2502) * libafl-fuzz: fix unicorn mode not using a deferred forkserver libafl-fuzz: simplify handling args for harness * fix unicorn_mode --------- Co-authored-by: Dominik Maier --- fuzzers/others/libafl-fuzz/Makefile.toml | 5 ++++- fuzzers/others/libafl-fuzz/src/executor.rs | 3 ++- fuzzers/others/libafl-fuzz/src/fuzzer.rs | 19 +++++-------------- fuzzers/others/libafl-fuzz/src/main.rs | 1 + .../others/libafl-fuzz/test/seeds_unicorn/in | 1 + .../libafl-fuzz/test/seeds_unicorn_cmpcov/in | 1 + 6 files changed, 14 insertions(+), 16 deletions(-) create mode 100644 fuzzers/others/libafl-fuzz/test/seeds_unicorn/in create mode 100644 fuzzers/others/libafl-fuzz/test/seeds_unicorn_cmpcov/in diff --git a/fuzzers/others/libafl-fuzz/Makefile.toml b/fuzzers/others/libafl-fuzz/Makefile.toml index 868ed12e00..88b53035d6 100644 --- a/fuzzers/others/libafl-fuzz/Makefile.toml +++ b/fuzzers/others/libafl-fuzz/Makefile.toml @@ -13,7 +13,7 @@ LLVM_CONFIG = { value = "llvm-config-18", condition = { env_not_set = [ "LLVM_CONFIG", ] } } AFL_VERSION = "598a3c6b5e24bd33e84b914e145810d39f88adf6" -AFL_DIR = { value = "./AFLplusplus" } +AFL_DIR = { value = "${PROJECT_DIR}/AFLplusplus" } AFL_CC_PATH = { value = "${AFL_DIR}/afl-clang-fast" } CC = { value = "clang" } @@ -204,12 +204,15 @@ script = ''' export AFL_PATH=${AFL_DIR} export AFL_CORES=1 export AFL_STATS_INTERVAL=1 + # TODO: test unicorn persistent mode once it's fixed on AFL++ + LIBAFL_DEBUG_OUTPUT=1 AFL_DEBUG=1 AFL_DEBUG_CHILD=1 timeout 15s ${FUZZER} -m 0 -U -i ./test/seeds_unicorn -o ./test/output-unicorn-python -- python3 ${AFL_DIR}/unicorn_mode/samples/python_simple/simple_test_harness.py @@ || true test -n "$( ls ./test/output-unicorn-python/fuzzer_main/queue/id:000003* 2>/dev/null )" || { echo "No new corpus entries found for Unicorn python3 mode" exit 1 } + export AFL_COMPCOV_LEVEL=2 LIBAFL_DEBUG_OUTPUT=1 AFL_DEBUG=1 AFL_DEBUG_CHILD=1 timeout 15s ${FUZZER} -m 0 -U -i ./test/seeds_unicorn_cmpcov -o ./test/output-unicorn-cmpcov -- python3 ${AFL_DIR}/unicorn_mode/samples/compcov_x64/compcov_test_harness.py @@ || true test -n "$( ls ./test/output-unicorn-cmpcov/fuzzer_main/queue/id:000002* 2>/dev/null )" || { diff --git a/fuzzers/others/libafl-fuzz/src/executor.rs b/fuzzers/others/libafl-fuzz/src/executor.rs index daff6e279a..0db9a8f34c 100644 --- a/fuzzers/others/libafl-fuzz/src/executor.rs +++ b/fuzzers/others/libafl-fuzz/src/executor.rs @@ -52,7 +52,8 @@ pub fn check_binary(opt: &mut Opt, shmem_env_var: &str) -> Result<(), Error> { } } let metadata = bin_path.metadata()?; - let is_reg = !bin_path.is_symlink() && !bin_path.is_dir(); + // AFL++ does not follow symlinks, BUT we do. + let is_reg = bin_path.is_file(); let bin_size = metadata.st_size(); let is_executable = metadata.permissions().mode() & 0o111 != 0; if !is_reg || !is_executable || bin_size < 4 { diff --git a/fuzzers/others/libafl-fuzz/src/fuzzer.rs b/fuzzers/others/libafl-fuzz/src/fuzzer.rs index 2da969cb0b..4cc9b079a4 100644 --- a/fuzzers/others/libafl-fuzz/src/fuzzer.rs +++ b/fuzzers/others/libafl-fuzz/src/fuzzer.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, env, marker::PhantomData, path::PathBuf, time::Duration}; +use std::{borrow::Cow, marker::PhantomData, path::PathBuf, time::Duration}; use libafl::{ corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus}, @@ -410,22 +410,11 @@ fn base_executor<'a>( if let Some(kill_signal) = opt.kill_signal { executor = executor.kill_signal(kill_signal); } - if opt.is_persistent || opt.qemu_mode { + if opt.is_persistent || opt.qemu_mode || opt.unicorn_mode { executor = executor.shmem_provider(shmem_provider); } // Set arguments for the target if necessary - let exec = opt.executable.display().to_string(); - // we skip all libafl-fuzz arguments. - let (mut skip, _) = env::args() - .enumerate() - .find(|i| i.1 == exec) - .expect("invariant; should never occur"); - // we need the binary to remain as an argument if we are in qemu_mode - if !opt.qemu_mode { - skip += 1; - } - let args = env::args().skip(skip); - for arg in args { + for arg in &opt.target_args { if arg == AFL_HARNESS_FILE_INPUT { let mut file = get_unique_std_input_file(); if let Some(ext) = &opt.input_ext { @@ -441,6 +430,8 @@ fn base_executor<'a>( } } if opt.qemu_mode { + // We need to give the harness as the first argument to afl-qemu-trace. + executor = executor.arg(opt.executable.clone()); executor = executor.program( find_afl_binary("afl-qemu-trace", Some(opt.executable.clone())) .expect("to find afl-qemu-trace"), diff --git a/fuzzers/others/libafl-fuzz/src/main.rs b/fuzzers/others/libafl-fuzz/src/main.rs index 69960a9b9a..78dd1d8159 100644 --- a/fuzzers/others/libafl-fuzz/src/main.rs +++ b/fuzzers/others/libafl-fuzz/src/main.rs @@ -111,6 +111,7 @@ fn main() { /// The Configuration struct Opt { executable: PathBuf, + target_args: Vec, // NOTE: afl-fuzz does not accept multiple input directories #[arg(short = 'i')] diff --git a/fuzzers/others/libafl-fuzz/test/seeds_unicorn/in b/fuzzers/others/libafl-fuzz/test/seeds_unicorn/in new file mode 100644 index 0000000000..573541ac97 --- /dev/null +++ b/fuzzers/others/libafl-fuzz/test/seeds_unicorn/in @@ -0,0 +1 @@ +0 diff --git a/fuzzers/others/libafl-fuzz/test/seeds_unicorn_cmpcov/in b/fuzzers/others/libafl-fuzz/test/seeds_unicorn_cmpcov/in new file mode 100644 index 0000000000..40fdece9d2 --- /dev/null +++ b/fuzzers/others/libafl-fuzz/test/seeds_unicorn_cmpcov/in @@ -0,0 +1 @@ + \ No newline at end of file