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 <domenukk@gmail.com>
This commit is contained in:
Aarnav 2024-08-26 19:30:38 +02:00 committed by GitHub
parent e2cc78f274
commit 3ca906b7d3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 14 additions and 16 deletions

View File

@ -13,7 +13,7 @@ LLVM_CONFIG = { value = "llvm-config-18", condition = { env_not_set = [
"LLVM_CONFIG", "LLVM_CONFIG",
] } } ] } }
AFL_VERSION = "598a3c6b5e24bd33e84b914e145810d39f88adf6" AFL_VERSION = "598a3c6b5e24bd33e84b914e145810d39f88adf6"
AFL_DIR = { value = "./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" }
@ -204,12 +204,15 @@ script = '''
export AFL_PATH=${AFL_DIR} export AFL_PATH=${AFL_DIR}
export AFL_CORES=1 export AFL_CORES=1
export AFL_STATS_INTERVAL=1 export AFL_STATS_INTERVAL=1
# TODO: test unicorn persistent mode once it's fixed on AFL++ # 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 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 )" || { 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" echo "No new corpus entries found for Unicorn python3 mode"
exit 1 exit 1
} }
export AFL_COMPCOV_LEVEL=2 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 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 )" || { test -n "$( ls ./test/output-unicorn-cmpcov/fuzzer_main/queue/id:000002* 2>/dev/null )" || {

View File

@ -52,7 +52,8 @@ pub fn check_binary(opt: &mut Opt, shmem_env_var: &str) -> Result<(), Error> {
} }
} }
let metadata = bin_path.metadata()?; 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 bin_size = metadata.st_size();
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 {

View File

@ -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::{ use libafl::{
corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus}, corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus},
@ -410,22 +410,11 @@ fn base_executor<'a>(
if let Some(kill_signal) = opt.kill_signal { if let Some(kill_signal) = opt.kill_signal {
executor = executor.kill_signal(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); executor = executor.shmem_provider(shmem_provider);
} }
// Set arguments for the target if necessary // Set arguments for the target if necessary
let exec = opt.executable.display().to_string(); for arg in &opt.target_args {
// 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 {
if arg == AFL_HARNESS_FILE_INPUT { if arg == AFL_HARNESS_FILE_INPUT {
let mut file = get_unique_std_input_file(); let mut file = get_unique_std_input_file();
if let Some(ext) = &opt.input_ext { if let Some(ext) = &opt.input_ext {
@ -441,6 +430,8 @@ fn base_executor<'a>(
} }
} }
if opt.qemu_mode { 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( executor = executor.program(
find_afl_binary("afl-qemu-trace", Some(opt.executable.clone())) find_afl_binary("afl-qemu-trace", Some(opt.executable.clone()))
.expect("to find afl-qemu-trace"), .expect("to find afl-qemu-trace"),

View File

@ -111,6 +111,7 @@ fn main() {
/// The Configuration /// The Configuration
struct Opt { struct Opt {
executable: PathBuf, executable: PathBuf,
target_args: Vec<String>,
// NOTE: afl-fuzz does not accept multiple input directories // NOTE: afl-fuzz does not accept multiple input directories
#[arg(short = 'i')] #[arg(short = 'i')]

View File

@ -0,0 +1 @@
0

View File

@ -0,0 +1 @@