Addison Crump 56b37bb4bd
Improve the libafl_libfuzzer corpus (#1539)
* improved libfuzzer corpus

* use .into() for converting ids to usize

* oops

* fix warning about unused arg

* fix some lingering CI errors

* actually save the last lmao
2023-11-03 17:33:38 +01:00

175 lines
5.4 KiB
Rust

use std::{
ffi::c_int,
fs::{read, write},
};
use libafl::{
corpus::{Corpus, HasTestcase, InMemoryCorpus, Testcase},
events::SimpleEventManager,
executors::{inprocess::TimeoutInProcessForkExecutor, ExitKind},
feedbacks::{CrashFeedbackFactory, TimeoutFeedbackFactory},
inputs::{BytesInput, HasBytesVec, HasTargetBytes},
mutators::{havoc_mutations_no_crossover, Mutator, StdScheduledMutator},
schedulers::QueueScheduler,
stages::StdTMinMutationalStage,
state::{HasCorpus, StdState},
Error, Fuzzer, StdFuzzer,
};
use libafl_bolts::{
rands::{RandomSeed, RomuDuoJrRand, StdRand},
shmem::{ShMemProvider, StdShMemProvider},
tuples::tuple_list,
AsSlice, HasLen,
};
use libafl_targets::LLVMCustomMutator;
use crate::{options::LibfuzzerOptions, CustomMutationStatus};
type TMinState =
StdState<BytesInput, InMemoryCorpus<BytesInput>, RomuDuoJrRand, InMemoryCorpus<BytesInput>>;
fn minimize_crash_with_mutator<M: Mutator<BytesInput, TMinState>>(
options: &LibfuzzerOptions,
harness: extern "C" fn(*const u8, usize) -> c_int,
mutator: M,
mut state: TMinState,
) -> Result<(), Error> {
let mut mgr = SimpleEventManager::printing();
assert_eq!(
options.dirs().len(),
1,
"Must provide exactly one input to minimise"
);
assert!(options.dirs()[0].exists(), "Input specified does not exist");
assert!(options.dirs()[0].is_file(), "Input specified is not a file");
let input = BytesInput::new(read(&options.dirs()[0])?);
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
let result = unsafe {
crate::libafl_libfuzzer_test_one_input(Some(harness), buf.as_ptr(), buf.len())
};
match result {
-2 => ExitKind::Crash,
_ => ExitKind::Ok,
}
};
let mut fuzzer = StdFuzzer::new(QueueScheduler::new(), (), ());
let shmem_provider = StdShMemProvider::new()?;
let mut executor = TimeoutInProcessForkExecutor::new(
&mut harness,
(),
&mut fuzzer,
&mut state,
&mut mgr,
options.timeout(),
shmem_provider,
)?;
let exit_kind = fuzzer.execute_input(&mut state, &mut executor, &mut mgr, &input)?;
let size = input.len();
let id = state.corpus_mut().add(Testcase::new(input))?;
match exit_kind {
ExitKind::Crash => {
let factory = CrashFeedbackFactory::default();
let tmin = StdTMinMutationalStage::new(
mutator,
factory,
if options.runs() == 0 {
128
} else {
options.runs()
},
);
let mut stages = tuple_list!(tmin);
fuzzer.fuzz_one(&mut stages, &mut executor, &mut state, &mut mgr)?;
}
ExitKind::Timeout => {
let factory = TimeoutFeedbackFactory::default();
let tmin = StdTMinMutationalStage::new(
mutator,
factory,
if options.runs() == 0 {
128
} else {
options.runs()
},
);
let mut stages = tuple_list!(tmin);
fuzzer.fuzz_one(&mut stages, &mut executor, &mut state, &mut mgr)?;
}
kind => unimplemented!("Unsupported exit kind for test minification: {:?}", kind),
}
let mut testcase = state.testcase_mut(id)?;
let input = testcase.load_input(state.corpus())?.bytes().to_vec();
drop(testcase);
if input.len() >= size {
eprintln!(
"Unable to reduce {}",
options.dirs()[0].as_path().as_os_str().to_str().unwrap()
);
} else {
let mut dest = options.artifact_prefix().dir().clone();
dest.push(format!(
"{}minimized-from-{}",
options.artifact_prefix().filename_prefix(),
options.dirs()[0].file_name().unwrap().to_str().unwrap()
));
write(&dest, input)?;
println!(
"Wrote minimised input to {}",
dest.file_name().unwrap().to_str().unwrap()
);
}
Ok(())
}
pub fn minimize_crash(
options: &LibfuzzerOptions,
harness: extern "C" fn(*const u8, usize) -> c_int,
) -> Result<(), Error> {
println!(
"Attempting to minimise a crash: {}",
options
.dirs()
.iter()
.map(|p| p
.to_str()
.expect("Couldn't render the filename as a string!"))
.collect::<Vec<_>>()
.join(", ")
);
let mutator_status = CustomMutationStatus::new();
let state = StdState::new(
StdRand::new(),
InMemoryCorpus::<BytesInput>::new(),
InMemoryCorpus::new(),
&mut (),
&mut (),
)?;
// TODO configure with mutation stacking options from libfuzzer
if mutator_status.custom_mutation {
let custom_mutator = unsafe {
LLVMCustomMutator::mutate_unchecked(StdScheduledMutator::new(
havoc_mutations_no_crossover(),
))
};
minimize_crash_with_mutator(options, harness, custom_mutator, state)
} else {
let std_mutator = StdScheduledMutator::new(havoc_mutations_no_crossover());
minimize_crash_with_mutator(options, harness, std_mutator, state)
}
}