From 0cce1e2b9148836b4ab75c3f1126f893de4cf168 Mon Sep 17 00:00:00 2001 From: Andrea Fioraldi Date: Tue, 21 Dec 2021 11:26:04 +0100 Subject: [PATCH] Update fuzzbench and fuzzbench_qemu, delete fuzzbench_gsoc --- fuzzers/fuzzbench/src/lib.rs | 34 +- fuzzers/fuzzbench_gsoc/.gitignore | 2 - fuzzers/fuzzbench_gsoc/Cargo.toml | 32 -- fuzzers/fuzzbench_gsoc/Makefile | 48 --- fuzzers/fuzzbench_gsoc/README.md | 17 - fuzzers/fuzzbench_gsoc/fuzz.c | 15 - fuzzers/fuzzbench_gsoc/src/bin/libafl_cc.rs | 36 -- fuzzers/fuzzbench_gsoc/src/bin/libafl_cxx.rs | 5 - fuzzers/fuzzbench_gsoc/src/lib.rs | 350 ------------------- fuzzers/fuzzbench_qemu/.gitignore | 3 +- fuzzers/fuzzbench_qemu/Makefile | 43 +++ fuzzers/fuzzbench_qemu/fuzz.c | 19 - fuzzers/fuzzbench_qemu/libfuzzer_main.c | 11 + fuzzers/fuzzbench_qemu/src/fuzzer.rs | 60 ++-- 14 files changed, 107 insertions(+), 568 deletions(-) delete mode 100644 fuzzers/fuzzbench_gsoc/.gitignore delete mode 100644 fuzzers/fuzzbench_gsoc/Cargo.toml delete mode 100644 fuzzers/fuzzbench_gsoc/Makefile delete mode 100644 fuzzers/fuzzbench_gsoc/README.md delete mode 100644 fuzzers/fuzzbench_gsoc/fuzz.c delete mode 100644 fuzzers/fuzzbench_gsoc/src/bin/libafl_cc.rs delete mode 100644 fuzzers/fuzzbench_gsoc/src/bin/libafl_cxx.rs delete mode 100644 fuzzers/fuzzbench_gsoc/src/lib.rs create mode 100644 fuzzers/fuzzbench_qemu/Makefile delete mode 100644 fuzzers/fuzzbench_qemu/fuzz.c create mode 100644 fuzzers/fuzzbench_qemu/libfuzzer_main.c diff --git a/fuzzers/fuzzbench/src/lib.rs b/fuzzers/fuzzbench/src/lib.rs index 821b9ab387..b0dbdb5483 100644 --- a/fuzzers/fuzzbench/src/lib.rs +++ b/fuzzers/fuzzbench/src/lib.rs @@ -1,4 +1,4 @@ -//! A singlethreade libfuzzer-like fuzzer that can auto-restart. +//! A singlethreaded libfuzzer-like fuzzer that can auto-restart. use clap::{App, Arg}; use core::{cell::RefCell, time::Duration}; @@ -28,14 +28,13 @@ use libafl::{ events::SimpleRestartingEventManager, executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor}, feedback_or, - feedbacks::{AflMapFeedback, CrashFeedback, MapFeedbackState, TimeFeedback}, + feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, mutators::{ - scheduled::{havoc_mutations, StdScheduledMutator}, - token_mutations::I2SRandReplace, - tokens_mutations, Tokens, + scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, + StdMOptMutator, StdScheduledMutator, Tokens, }, observers::{HitcountsMapObserver, StdMapObserver, TimeObserver}, stages::{ @@ -176,7 +175,7 @@ fn fuzz( #[cfg(unix)] let file_null = File::open("/dev/null")?; - // 'While the stats are state, they are usually used in the broker - which is likely never restarted + // 'While the monitor are state, they are usually used in the broker - which is likely never restarted let monitor = SimpleMonitor::new(|s| { #[cfg(unix)] writeln!(&mut stdout_cpy, "{}", s).unwrap(); @@ -221,7 +220,7 @@ fn fuzz( // This one is composed by two Feedbacks in OR let feedback = feedback_or!( // New maximization map feedback linked to the edges observer and the feedback state - AflMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), + MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), // Time feedback, this one does not need a feedback state TimeFeedback::new_with_observer(&time_observer) ); @@ -255,13 +254,17 @@ fn fuzz( } let calibration = CalibrationStage::new(&mut state, &edges_observer); - let mutator = StdScheduledMutator::new(havoc_mutations()); + + // Setup a randomic Input2State stage + let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(I2SRandReplace::new()))); + + // Setup a MOPT mutator + let mutator = StdMOptMutator::new(&mut state, havoc_mutations().merge(tokens_mutations()), 5)?; let power = PowerMutationalStage::new(mutator, PowerSchedule::FAST, &edges_observer); - let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(PowerQueueCorpusScheduler::new()); // A minimization+queue policy to get testcasess from the corpus - //let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(QueueCorpusScheduler::new()); + let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(PowerQueueCorpusScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); @@ -301,15 +304,8 @@ fn fuzz( timeout * 10, )); - // Setup a randomic Input2State stage - let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(I2SRandReplace::new()))); - - // Setup a basic mutator - let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); - let mutational = StdMutationalStage::new(mutator); - // The order of the stages matter! - let mut stages = tuple_list!(calibration, tracing, i2s, mutational, power); + let mut stages = tuple_list!(calibration, tracing, i2s, power); // Read tokens if let Some(tokenfile) = tokenfile { @@ -336,7 +332,6 @@ fn fuzz( dup2(null_fd, io::stdout().as_raw_fd())?; dup2(null_fd, io::stderr().as_raw_fd())?; } - // reopen file to make sure we're at the end log.replace( OpenOptions::new() @@ -350,3 +345,4 @@ fn fuzz( // Never reached Ok(()) } + diff --git a/fuzzers/fuzzbench_gsoc/.gitignore b/fuzzers/fuzzbench_gsoc/.gitignore deleted file mode 100644 index d3561edaf7..0000000000 --- a/fuzzers/fuzzbench_gsoc/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -libpng-* -fuzzer diff --git a/fuzzers/fuzzbench_gsoc/Cargo.toml b/fuzzers/fuzzbench_gsoc/Cargo.toml deleted file mode 100644 index e728c5d9c4..0000000000 --- a/fuzzers/fuzzbench_gsoc/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -name = "fuzzbench" -version = "0.7.0" -authors = ["Andrea Fioraldi ", "Dominik Maier "] -edition = "2021" - -[features] -default = ["std"] -std = [] - -[profile.release] -lto = true -codegen-units = 1 -opt-level = 3 -debug = true - -[build-dependencies] -cc = { version = "1.0", features = ["parallel"] } -which = { version = "4.0.2" } -num_cpus = "1.0" - -[dependencies] -libafl = { path = "../../libafl/" } -libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_hitcounts", "sancov_cmplog", "libfuzzer"] } -# TODO Include it only when building cc -libafl_cc = { path = "../../libafl_cc/" } -clap = { version = "3.0.0-rc.4", features = ["default"] } -nix = "0.23.0" - -[lib] -name = "fuzzbench" -crate-type = ["staticlib"] diff --git a/fuzzers/fuzzbench_gsoc/Makefile b/fuzzers/fuzzbench_gsoc/Makefile deleted file mode 100644 index cdedd036d5..0000000000 --- a/fuzzers/fuzzbench_gsoc/Makefile +++ /dev/null @@ -1,48 +0,0 @@ -FUZZER_NAME="fuzzer" -PROJECT_DIR=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) - -PHONY: all - -all: fuzzer - -target/release/libafl_cxx: src/* src/bin/* - # Build the libpng libfuzzer library - cargo build --release - -target/release/libafl_cc: target/release/libafl_cxx - -fuzz.o: fuzz.c target/release/libafl_cc - target/release/libafl_cc -O3 -c $^ -o $@ - -fuzzer: target/release/libafl_cxx fuzz.o - # Build the fuzzer compiler - cargo build --release - - # Build the harness - target/release/libafl_cxx \ - fuzz.o \ - -o $(FUZZER_NAME) \ - -lm -lz - -clean: - rm ./$(FUZZER_NAME) || true - rm fuzz.o || true - -run: all - ./$(FUZZER_NAME) - -short_test: all - rm -rf libafl_unix_shmem_server || true - mkdir in || true - echo a > in/a - # Allow sigterm as exit code - (timeout 11s ./$(FUZZER_NAME) out in || [ $$? -eq 124 ]) - rm -rf out || true - rm -rf in || true - -test: all - mkdir in || true - echo a > in/a - (timeout 60s ./$(FUZZER_NAME) out in || [ $$? -eq 124 ]) - rm -rf out || true - rm -rf in || true diff --git a/fuzzers/fuzzbench_gsoc/README.md b/fuzzers/fuzzbench_gsoc/README.md deleted file mode 100644 index df34f5e090..0000000000 --- a/fuzzers/fuzzbench_gsoc/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Fuzzbench Harness - -This folder contains an example fuzzer tailored for fuzzbench. -It uses the best possible setting, with the exception of a SimpleRestartingEventManager instead of an LlmpEventManager - since fuzzbench is single threaded. -Real fuzz campaigns should consider using multithreaded LlmpEventManager, see the other examples. - -## Build - -To build this example, run `cargo build --release`. -This will build the fuzzer compilers (`libafl_cc` and `libafl_cpp`) with `src/lib.rs` as fuzzer. -The fuzzer uses the libfuzzer compatibility layer and the SanitizerCoverage runtime functions for coverage feedback. - -These can then be used to build libfuzzer harnesses in the software project of your choice. -Finally, just run the resulting binary with `out_dir`, `in_dir`. - -In any real-world scenario, you should use `taskset` to pin each client to an empty CPU core, the lib does not pick an empty core automatically (yet). - diff --git a/fuzzers/fuzzbench_gsoc/fuzz.c b/fuzzers/fuzzbench_gsoc/fuzz.c deleted file mode 100644 index 7eea9f3b30..0000000000 --- a/fuzzers/fuzzbench_gsoc/fuzz.c +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include - -int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - if (Size >= 8 && *(uint32_t*)Data == 0xaabbccdd) - abort(); -} - -/* -int main() { - - char buf [10] = {0}; - LLVMFuzzerTestOneInput(buf, 10); - -}*/ diff --git a/fuzzers/fuzzbench_gsoc/src/bin/libafl_cc.rs b/fuzzers/fuzzbench_gsoc/src/bin/libafl_cc.rs deleted file mode 100644 index c84bfceddd..0000000000 --- a/fuzzers/fuzzbench_gsoc/src/bin/libafl_cc.rs +++ /dev/null @@ -1,36 +0,0 @@ -use libafl_cc::{ClangWrapper, CompilerWrapper, LLVMPasses}; -use std::env; - -pub fn main() { - let args: Vec = env::args().collect(); - if args.len() > 1 { - let mut dir = env::current_exe().unwrap(); - let wrapper_name = dir.file_name().unwrap().to_str().unwrap(); - - let is_cpp = match wrapper_name[wrapper_name.len()-2..].to_lowercase().as_str() { - "cc" => false, - "++" | "pp" | "xx" => true, - _ => panic!("Could not figure out if c or c++ warpper was called. Expected {:?} to end with c or cxx", dir), - }; - - dir.pop(); - - let mut cc = ClangWrapper::new(); - if let Some(code) = cc - .cpp(is_cpp) - // silence the compiler wrapper output, needed for some configure scripts. - .silence(true) - .from_args(&args) - .expect("Failed to parse the command line") - .link_staticlib(&dir, "fuzzbench") - .add_arg("-fsanitize-coverage=trace-pc-guard,trace-cmp") - .add_pass(LLVMPasses::CmpLogRtn) - .run() - .expect("Failed to run the wrapped compiler") - { - std::process::exit(code); - } - } else { - panic!("LibAFL CC: No Arguments given"); - } -} diff --git a/fuzzers/fuzzbench_gsoc/src/bin/libafl_cxx.rs b/fuzzers/fuzzbench_gsoc/src/bin/libafl_cxx.rs deleted file mode 100644 index ce786239b0..0000000000 --- a/fuzzers/fuzzbench_gsoc/src/bin/libafl_cxx.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod libafl_cc; - -fn main() { - libafl_cc::main() -} diff --git a/fuzzers/fuzzbench_gsoc/src/lib.rs b/fuzzers/fuzzbench_gsoc/src/lib.rs deleted file mode 100644 index 5de783b1b3..0000000000 --- a/fuzzers/fuzzbench_gsoc/src/lib.rs +++ /dev/null @@ -1,350 +0,0 @@ -//! A singlethreade libfuzzer-like fuzzer that can auto-restart. - -use clap::{App, Arg}; -use core::{cell::RefCell, time::Duration}; -#[cfg(unix)] -use nix::{self, unistd::dup}; -#[cfg(unix)] -use std::os::unix::io::{AsRawFd, FromRawFd}; -use std::{ - env, - fs::{self, File, OpenOptions}, - io::{self, Write}, - path::PathBuf, - process, -}; - -use libafl::{ - bolts::{ - current_nanos, current_time, - os::dup2, - rands::StdRand, - shmem::{ShMemProvider, StdShMemProvider}, - tuples::{tuple_list, Merge}, - }, - corpus::{ - Corpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, PowerQueueCorpusScheduler, - }, - events::SimpleRestartingEventManager, - executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor}, - feedback_or, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback}, - fuzzer::{Fuzzer, StdFuzzer}, - inputs::{BytesInput, HasTargetBytes}, - monitors::SimpleMonitor, - mutators::{ - scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, - StdMOptMutator, Tokens, - }, - observers::{StdMapObserver, TimeObserver}, - stages::{ - calibrate::CalibrationStage, - power::{PowerMutationalStage, PowerSchedule}, - TracingStage, - }, - state::{HasCorpus, HasMetadata, StdState}, - Error, -}; -use libafl_targets::{ - libfuzzer_initialize, libfuzzer_test_one_input, CmpLogObserver, CMPLOG_MAP, EDGES_MAP, - MAX_EDGES_NUM, -}; - -/// The fuzzer main (as `no_mangle` C function) -#[no_mangle] -pub fn libafl_main() { - // Registry the metadata types used in this fuzzer - // Needed only on no_std - //RegistryBuilder::register::(); - - let res = match App::new("libafl_fuzzbench") - .version("0.4.0") - .author("AFLplusplus team") - .about("LibAFL-based fuzzer for Fuzzbench") - .arg( - Arg::new("out") - .help("The directory to place finds in ('corpus')") - .required(true) - .index(1) - .takes_value(true), - ) - .arg( - Arg::new("in") - .help("The directory to read initial inputs from ('seeds')") - .required(true) - .index(2) - .takes_value(true), - ) - .arg( - Arg::new("tokens") - .short('x') - .long("tokens") - .help("A file to read tokens from, to be used during fuzzing") - .takes_value(true), - ) - .arg( - Arg::new("logfile") - .short('l') - .long("logfile") - .help("Duplicates all output to this file") - .default_value("libafl.log"), - ) - .arg( - Arg::new("timeout") - .short('t') - .long("timeout") - .help("Timeout for each individual execution, in milliseconds") - .default_value("1200"), - ) - .try_get_matches() - { - Ok(res) => res, - Err(err) => { - println!( - "Syntax: {}, [-x dictionary] corpus_dir seed_dir\n{:?}", - env::current_exe() - .unwrap_or_else(|_| "fuzzer".into()) - .to_string_lossy(), - err.info, - ); - return; - } - }; - - println!( - "Workdir: {:?}", - env::current_dir().unwrap().to_string_lossy().to_string() - ); - - // For fuzzbench, crashes and finds are inside the same `corpus` directory, in the "queue" and "crashes" subdir. - let mut out_dir = PathBuf::from(res.value_of("out").unwrap().to_string()); - if fs::create_dir(&out_dir).is_err() { - println!("Out dir at {:?} already exists.", &out_dir); - if !out_dir.is_dir() { - println!("Out dir at {:?} is not a valid directory!", &out_dir); - return; - } - } - let mut crashes = out_dir.clone(); - crashes.push("crashes"); - out_dir.push("queue"); - - let in_dir = PathBuf::from(res.value_of("in").unwrap().to_string()); - if !in_dir.is_dir() { - println!("In dir at {:?} is not a valid directory!", &in_dir); - return; - } - - let tokens = res.value_of("tokens").map(PathBuf::from); - - let logfile = PathBuf::from(res.value_of("logfile").unwrap().to_string()); - - let timeout = Duration::from_millis( - res.value_of("timeout") - .unwrap() - .to_string() - .parse() - .expect("Could not parse timeout in milliseconds"), - ); - - fuzz(out_dir, crashes, in_dir, tokens, logfile, timeout) - .expect("An error occurred while fuzzing"); -} - -/// The actual fuzzer -fn fuzz( - corpus_dir: PathBuf, - objective_dir: PathBuf, - seed_dir: PathBuf, - tokenfile: Option, - logfile: PathBuf, - timeout: Duration, -) -> Result<(), Error> { - let log = RefCell::new( - OpenOptions::new() - .append(true) - .create(true) - .open(&logfile)?, - ); - - #[cfg(unix)] - let mut stdout_cpy = unsafe { - let new_fd = dup(io::stdout().as_raw_fd())?; - File::from_raw_fd(new_fd) - }; - #[cfg(unix)] - let file_null = File::open("/dev/null")?; - - // 'While the monitor are state, they are usually used in the broker - which is likely never restarted - let monitor = SimpleMonitor::new(|s| { - #[cfg(unix)] - writeln!(&mut stdout_cpy, "{}", s).unwrap(); - #[cfg(windows)] - println!("{}", s); - writeln!(log.borrow_mut(), "{:?} {}", current_time(), s).unwrap(); - }); - - // We need a shared map to store our state before a crash. - // This way, we are able to continue fuzzing afterwards. - let mut shmem_provider = StdShMemProvider::new()?; - - let (state, mut mgr) = match SimpleRestartingEventManager::launch(monitor, &mut shmem_provider) - { - // The restarting state will spawn the same process again as child, then restarted it each time it crashes. - Ok(res) => res, - Err(err) => match err { - Error::ShuttingDown => { - return Ok(()); - } - _ => { - panic!("Failed to setup the restarter: {}", err); - } - }, - }; - - // Create an observation channel using the coverage map - // We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges) - let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] }; - let edges_observer = StdMapObserver::new("edges", edges); - - // Create an observation channel to keep track of the execution time - let time_observer = TimeObserver::new("time"); - - let cmplog = unsafe { &mut CMPLOG_MAP }; - let cmplog_observer = CmpLogObserver::new("cmplog", cmplog, true); - - // The state of the edges feedback. - let feedback_state = MapFeedbackState::with_observer(&edges_observer); - - // Feedback to rate the interestingness of an input - // This one is composed by two Feedbacks in OR - let feedback = feedback_or!( - // New maximization map feedback linked to the edges observer and the feedback state - MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), - // Time feedback, this one does not need a feedback state - TimeFeedback::new_with_observer(&time_observer) - ); - - // A feedback to choose if an input is a solution or not - let objective = CrashFeedback::new(); - - // If not restarting, create a State from scratch - let mut state = state.unwrap_or_else(|| { - StdState::new( - // RNG - StdRand::with_seed(current_nanos()), - // Corpus that will be evolved, we keep it in memory for performance - OnDiskCorpus::new(corpus_dir).unwrap(), - // Corpus in which we store solutions (crashes in this example), - // on disk so the user can get them after stopping the fuzzer - OnDiskCorpus::new(objective_dir).unwrap(), - // States of the feedbacks. - // They are the data related to the feedbacks that you want to persist in the State. - tuple_list!(feedback_state), - ) - }); - - println!("Let's fuzz :)"); - - // The actual target run starts here. - // Call LLVMFUzzerInitialize() if present. - let args: Vec = env::args().collect(); - if libfuzzer_initialize(&args) == -1 { - println!("Warning: LLVMFuzzerInitialize failed with -1") - } - - let calibration = CalibrationStage::new(&mut state, &edges_observer); - - // Setup a MOPT mutator - let mutator = StdMOptMutator::new( - &mut state, - havoc_mutations() - .merge(tokens_mutations()) - .merge(tuple_list!(I2SRandReplace::new())), - 5, - )?; - - let power = PowerMutationalStage::new(mutator, PowerSchedule::FAST, &edges_observer); - - // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(PowerQueueCorpusScheduler::new()); - - // A fuzzer with feedbacks and a corpus scheduler - let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); - - // The wrapped harness function, calling out to the LLVM-style harness - let mut harness = |input: &BytesInput| { - let target = input.target_bytes(); - let buf = target.as_slice(); - libfuzzer_test_one_input(buf); - ExitKind::Ok - }; - - let mut tracing_harness = harness; - - // Create the executor for an in-process function with one observer for edge coverage and one for the execution time - let mut executor = TimeoutExecutor::new( - InProcessExecutor::new( - &mut harness, - tuple_list!(edges_observer, time_observer), - &mut fuzzer, - &mut state, - &mut mgr, - )?, - timeout, - ); - - // Setup a tracing stage in which we log comparisons - let tracing = TracingStage::new(TimeoutExecutor::new( - InProcessExecutor::new( - &mut tracing_harness, - tuple_list!(cmplog_observer), - &mut fuzzer, - &mut state, - &mut mgr, - )?, - // Give it more time! - timeout * 10, - )); - - // The order of the stages matter! - let mut stages = tuple_list!(calibration, tracing, power); - - // Read tokens - if let Some(tokenfile) = tokenfile { - if state.metadata().get::().is_none() { - state.add_metadata(Tokens::from_tokens_file(tokenfile)?); - } - } - - // In case the corpus is empty (on first run), reset - if state.corpus().count() < 1 { - state - .load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &[seed_dir.clone()]) - .unwrap_or_else(|_| { - println!("Failed to load initial corpus at {:?}", &seed_dir); - process::exit(0); - }); - println!("We imported {} inputs from disk.", state.corpus().count()); - } - - // Remove target ouput (logs still survive) - #[cfg(unix)] - { - let null_fd = file_null.as_raw_fd(); - dup2(null_fd, io::stdout().as_raw_fd())?; - dup2(null_fd, io::stderr().as_raw_fd())?; - } - // reopen file to make sure we're at the end - log.replace( - OpenOptions::new() - .append(true) - .create(true) - .open(&logfile)?, - ); - - fuzzer.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)?; - - // Never reached - Ok(()) -} diff --git a/fuzzers/fuzzbench_qemu/.gitignore b/fuzzers/fuzzbench_qemu/.gitignore index 47166ca405..a977a2ca5b 100644 --- a/fuzzers/fuzzbench_qemu/.gitignore +++ b/fuzzers/fuzzbench_qemu/.gitignore @@ -1,2 +1 @@ -build/ -qemu-libafl-bridge/ +libpng-* \ No newline at end of file diff --git a/fuzzers/fuzzbench_qemu/Makefile b/fuzzers/fuzzbench_qemu/Makefile new file mode 100644 index 0000000000..a1c3e4ab6a --- /dev/null +++ b/fuzzers/fuzzbench_qemu/Makefile @@ -0,0 +1,43 @@ +FUZZER_NAME="libpng_harness" +PROJECT_DIR=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) +UNAME := $(shell uname) + +PHONY: all + +all: fuzzer + +libpng-1.6.37: + wget https://deac-fra.dl.sourceforge.net/project/libpng/libpng16/1.6.37/libpng-1.6.37.tar.xz + tar -xvf libpng-1.6.37.tar.xz + +target/release/fuzzbench_qemu: src/* + cargo build --release + +libpng-1.6.37/.libs/libpng16.a: libpng-1.6.37 + cd libpng-1.6.37 && ./configure --enable-shared=no --with-pic=yes --enable-hardware-optimizations=yes + $(MAKE) -C libpng-1.6.37 + cc -c $(PROJECT_DIR)/libfuzzer_main.c + # Build the libpng harness + c++ \ + $(PROJECT_DIR)/../libfuzzer_libpng/harness.cc \ + $(PROJECT_DIR)/libpng-1.6.37/.libs/libpng16.a \ + libfuzzer_main.o \ + -I$(PROJECT_DIR)/libpng-1.6.37/ \ + -o $(FUZZER_NAME) \ + -lm -lz + +fuzzer: target/release/fuzzbench_qemu libpng-1.6.37/.libs/libpng16.a + +clean: + rm ./$(FUZZER_NAME) libfuzzer_main.o + $(MAKE) -C libpng-1.6.37 clean + +run: all + cargo run --release -- --libafl-in ../libfuzzer_libpng/corpus --libafl-out ./out ./$(FUZZER_NAME) + +short_test: all + rm -rf libafl_unix_shmem_server || true + timeout 10s cargo run --release -- --libafl-in ../libfuzzer_libpng/corpus --libafl-out ./out ./$(FUZZER_NAME) & + +test: all + timeout 60s cargo run --release -- --libafl-in ../libfuzzer_libpng/corpus --libafl-out ./out ./$(FUZZER_NAME) & diff --git a/fuzzers/fuzzbench_qemu/fuzz.c b/fuzzers/fuzzbench_qemu/fuzz.c deleted file mode 100644 index d3fd13c603..0000000000 --- a/fuzzers/fuzzbench_qemu/fuzz.c +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include -#include - -char o = 0; - -int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { - // printf("Got %ld bytes.\n", Size); - o += 1; - if (Size >= 4 && *(uint32_t*)Data == 0xaabbccdd) - abort(); -} - -int main() { - - char buf [10] = {0}; - LLVMFuzzerTestOneInput(buf, 10); - -} diff --git a/fuzzers/fuzzbench_qemu/libfuzzer_main.c b/fuzzers/fuzzbench_qemu/libfuzzer_main.c new file mode 100644 index 0000000000..a834699f30 --- /dev/null +++ b/fuzzers/fuzzbench_qemu/libfuzzer_main.c @@ -0,0 +1,11 @@ +#include +#include + +int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size); + +int main() { + + char buf [10] = {0}; + LLVMFuzzerTestOneInput(buf, 10); + +} diff --git a/fuzzers/fuzzbench_qemu/src/fuzzer.rs b/fuzzers/fuzzbench_qemu/src/fuzzer.rs index af857ccf37..6787ae9fc0 100644 --- a/fuzzers/fuzzbench_qemu/src/fuzzer.rs +++ b/fuzzers/fuzzbench_qemu/src/fuzzer.rs @@ -22,33 +22,42 @@ use libafl::{ shmem::{ShMemProvider, StdShMemProvider}, tuples::{tuple_list, Merge}, }, - corpus::{Corpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, QueueCorpusScheduler}, + corpus::{ + Corpus, IndexesLenTimeMinimizerCorpusScheduler, OnDiskCorpus, PowerQueueCorpusScheduler, + }, events::SimpleRestartingEventManager, executors::{ExitKind, ShadowExecutor, TimeoutExecutor}, - feedback_or, feedback_or_fast, - feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, + feedback_or, + feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback}, fuzzer::{Fuzzer, StdFuzzer}, inputs::{BytesInput, HasTargetBytes}, monitors::SimpleMonitor, mutators::{ - scheduled::{havoc_mutations, StdScheduledMutator}, - tokens_mutations, I2SRandReplace, Tokens, + scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, + StdMOptMutator, StdScheduledMutator, Tokens, }, observers::{HitcountsMapObserver, TimeObserver, VariableMapObserver}, - stages::{ShadowTracingStage, StdMutationalStage}, + stages::{ + calibrate::CalibrationStage, + power::{PowerMutationalStage, PowerSchedule}, + ShadowTracingStage, StdMutationalStage, + }, state::{HasCorpus, HasMetadata, StdState}, Error, }; use libafl_qemu::{ - asan::QemuAsanHelper, + //asan::QemuAsanHelper, cmplog, cmplog::{CmpLogObserver, QemuCmpLogHelper}, edges, edges::QemuEdgeCoverageHelper, elf::EasyElf, - emu, filter_qemu_args, init_with_asan, - snapshot::QemuSnapshotHelper, - MmapPerms, QemuExecutor, Regs, + emu, + filter_qemu_args, + //snapshot::QemuSnapshotHelper, + MmapPerms, + QemuExecutor, + Regs, }; /// The fuzzer main @@ -57,9 +66,9 @@ pub fn main() { // Needed only on no_std //RegistryBuilder::register::(); - let mut args: Vec = env::args().collect(); - let mut env: Vec<(String, String)> = env::vars().collect(); - init_with_asan(&mut args, &mut env); + let args: Vec = env::args().collect(); + let env: Vec<(String, String)> = env::vars().collect(); + emu::init(&args, &env); let res = match App::new("libafl_qemu_fuzzbench") .version("0.4.0") @@ -256,7 +265,7 @@ fn fuzz( ); // A feedback to choose if an input is a solution or not - let objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new()); + let objective = CrashFeedback::new(); // create a State from scratch let mut state = state.unwrap_or_else(|| { @@ -274,8 +283,18 @@ fn fuzz( ) }); + let calibration = CalibrationStage::new(&mut state, &edges_observer); + + // Setup a randomic Input2State stage + let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(I2SRandReplace::new()))); + + // Setup a MOPT mutator + let mutator = StdMOptMutator::new(&mut state, havoc_mutations().merge(tokens_mutations()), 5)?; + + let power = PowerMutationalStage::new(mutator, PowerSchedule::FAST, &edges_observer); + // A minimization+queue policy to get testcasess from the corpus - let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(QueueCorpusScheduler::new()); + let scheduler = IndexesLenTimeMinimizerCorpusScheduler::new(PowerQueueCorpusScheduler::new()); // A fuzzer with feedbacks and a corpus scheduler let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); @@ -307,7 +326,7 @@ fn fuzz( tuple_list!( QemuEdgeCoverageHelper::new(), QemuCmpLogHelper::new(), - QemuAsanHelper::new(), + //QemuAsanHelper::new(), //QemuSnapshotHelper::new() ), tuple_list!(edges_observer, time_observer), @@ -340,13 +359,8 @@ fn fuzz( let tracing = ShadowTracingStage::new(&mut executor); - // Setup a randomic Input2State stage - let i2s = StdMutationalStage::new(I2SRandReplace::new()); - - // Setup a mutational stage with a basic bytes mutator - let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations())); - - let mut stages = tuple_list!(tracing, i2s, StdMutationalStage::new(mutator)); + // The order of the stages matter! + let mut stages = tuple_list!(calibration, tracing, i2s, power); // Remove target ouput (logs still survive) #[cfg(unix)]