syheliel 2504b6dae3
Add rustfmt.toml (#722)
* add `rustfmt.toml`

* format fix

Co-authored-by: syheliel <syheliel@gmail.com>
2022-08-12 02:28:32 +02:00

174 lines
5.7 KiB
Rust

#[cfg(windows)]
use std::ptr::write_volatile;
use std::{fs, io::Read, path::PathBuf};
use libafl::{
bolts::{current_nanos, rands::StdRand, tuples::tuple_list, AsSlice},
corpus::{InMemoryCorpus, OnDiskCorpus},
events::SimpleEventManager,
executors::{inprocess::InProcessExecutor, ExitKind},
feedbacks::{CrashFeedback, MaxMapFeedback},
fuzzer::{Evaluator, Fuzzer, StdFuzzer},
inputs::{GeneralizedInput, HasTargetBytes},
monitors::SimpleMonitor,
mutators::{
havoc_mutations, scheduled::StdScheduledMutator, GrimoireExtensionMutator,
GrimoireRandomDeleteMutator, GrimoireRecursiveReplacementMutator,
GrimoireStringReplacementMutator, Tokens,
},
observers::StdMapObserver,
schedulers::QueueScheduler,
stages::{mutational::StdMutationalStage, GeneralizationStage},
state::{HasMetadata, StdState},
};
/// Coverage map with explicit assignments due to the lack of instrumentation
static mut SIGNALS: [u8; 16] = [0; 16];
/// Assign a signal to the signals map
fn signals_set(idx: usize) {
unsafe { SIGNALS[idx] = 1 };
}
fn is_sub<T: PartialEq>(mut haystack: &[T], needle: &[T]) -> bool {
if needle.is_empty() {
return true;
}
while !haystack.is_empty() {
if haystack.starts_with(needle) {
return true;
}
haystack = &haystack[1..];
}
false
}
#[allow(clippy::similar_names)]
pub fn main() {
let mut initial_inputs = vec![];
for entry in fs::read_dir("./corpus").unwrap() {
let path = entry.unwrap().path();
let attr = fs::metadata(&path);
if attr.is_err() {
continue;
}
let attr = attr.unwrap();
if attr.is_file() && attr.len() > 0 {
println!("Loading file {:?} ...", &path);
let mut file = fs::File::open(path).expect("no file found");
let mut buffer = vec![];
file.read_to_end(&mut buffer).expect("buffer overflow");
let input = GeneralizedInput::new(buffer);
initial_inputs.push(input);
}
}
// The closure that we want to fuzz
let mut harness = |input: &GeneralizedInput| {
let target_bytes = input.target_bytes();
let bytes = target_bytes.as_slice();
if is_sub(bytes, "fn".as_bytes()) {
signals_set(2);
}
if is_sub(bytes, "pippopippo".as_bytes()) {
signals_set(3);
}
unsafe {
if input.grimoire_mutated {
// println!(">>> {:?}", input.generalized());
println!(">>> {:?}", std::str::from_utf8_unchecked(bytes));
}
}
signals_set(1);
ExitKind::Ok
};
// Create an observation channel using the signals map
let observer = StdMapObserver::new("signals", unsafe { &mut SIGNALS });
// Feedback to rate the interestingness of an input
let mut feedback = MaxMapFeedback::new_tracking(&observer, false, true);
// A feedback to choose if an input is a solution or not
let mut objective = CrashFeedback::new();
// create a State from scratch
let mut state = StdState::new(
// RNG
StdRand::with_seed(current_nanos()),
// Corpus that will be evolved, we keep it in memory for performance
InMemoryCorpus::new(),
// Corpus in which we store solutions (crashes in this example),
// on disk so the user can get them after stopping the fuzzer
OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(),
// States of the feedbacks.
// The feedbacks can report the data that should persist in the State.
&mut feedback,
// Same for objective feedbacks
&mut objective,
)
.unwrap();
if state.metadata().get::<Tokens>().is_none() {
state.add_metadata(Tokens::from([b"FOO".to_vec(), b"BAR".to_vec()]));
}
// The Monitor trait define how the fuzzer stats are reported to the user
let monitor = SimpleMonitor::new(|s| println!("{}", s));
// The event manager handle the various events generated during the fuzzing loop
// such as the notification of the addition of a new item to the corpus
let mut mgr = SimpleEventManager::new(monitor);
// A queue policy to get testcasess from the corpus
let scheduler = QueueScheduler::new();
// A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
let generalization = GeneralizationStage::new(&observer);
// Create the executor for an in-process function with just one observer
let mut executor = InProcessExecutor::new(
&mut harness,
tuple_list!(observer),
&mut fuzzer,
&mut state,
&mut mgr,
)
.expect("Failed to create the Executor");
// Setup a mutational stage with a basic bytes mutator
let mutator = StdScheduledMutator::with_max_stack_pow(havoc_mutations(), 2);
let grimoire_mutator = StdScheduledMutator::with_max_stack_pow(
tuple_list!(
GrimoireExtensionMutator::new(),
GrimoireRecursiveReplacementMutator::new(),
GrimoireStringReplacementMutator::new(),
// give more probability to avoid large inputs
GrimoireRandomDeleteMutator::new(),
GrimoireRandomDeleteMutator::new(),
),
3,
);
let mut stages = tuple_list!(
generalization,
StdMutationalStage::new(mutator),
StdMutationalStage::new(grimoire_mutator)
);
for input in initial_inputs {
fuzzer
.evaluate_input(&mut state, &mut executor, &mut mgr, input)
.unwrap();
}
fuzzer
.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)
.expect("Error in the fuzzing loop");
}