Update fuzzbench and fuzzbench_qemu, delete fuzzbench_gsoc
This commit is contained in:
parent
2aa0ca5ef1
commit
0cce1e2b91
@ -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(())
|
||||
}
|
||||
|
||||
|
2
fuzzers/fuzzbench_gsoc/.gitignore
vendored
2
fuzzers/fuzzbench_gsoc/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
libpng-*
|
||||
fuzzer
|
@ -1,32 +0,0 @@
|
||||
[package]
|
||||
name = "fuzzbench"
|
||||
version = "0.7.0"
|
||||
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
||||
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"]
|
@ -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
|
@ -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).
|
||||
|
@ -1,15 +0,0 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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);
|
||||
|
||||
}*/
|
@ -1,36 +0,0 @@
|
||||
use libafl_cc::{ClangWrapper, CompilerWrapper, LLVMPasses};
|
||||
use std::env;
|
||||
|
||||
pub fn main() {
|
||||
let args: Vec<String> = 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");
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
pub mod libafl_cc;
|
||||
|
||||
fn main() {
|
||||
libafl_cc::main()
|
||||
}
|
@ -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::<Tokens>();
|
||||
|
||||
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<PathBuf>,
|
||||
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<String> = 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::<Tokens>().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(())
|
||||
}
|
3
fuzzers/fuzzbench_qemu/.gitignore
vendored
3
fuzzers/fuzzbench_qemu/.gitignore
vendored
@ -1,2 +1 @@
|
||||
build/
|
||||
qemu-libafl-bridge/
|
||||
libpng-*
|
43
fuzzers/fuzzbench_qemu/Makefile
Normal file
43
fuzzers/fuzzbench_qemu/Makefile
Normal file
@ -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) &
|
@ -1,19 +0,0 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
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);
|
||||
|
||||
}
|
11
fuzzers/fuzzbench_qemu/libfuzzer_main.c
Normal file
11
fuzzers/fuzzbench_qemu/libfuzzer_main.c
Normal file
@ -0,0 +1,11 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
|
||||
|
||||
int main() {
|
||||
|
||||
char buf [10] = {0};
|
||||
LLVMFuzzerTestOneInput(buf, 10);
|
||||
|
||||
}
|
@ -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::<Tokens>();
|
||||
|
||||
let mut args: Vec<String> = env::args().collect();
|
||||
let mut env: Vec<(String, String)> = env::vars().collect();
|
||||
init_with_asan(&mut args, &mut env);
|
||||
let args: Vec<String> = 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)]
|
||||
|
Loading…
x
Reference in New Issue
Block a user