small improvements

This commit is contained in:
Alwin Berger 2022-02-03 21:19:17 +01:00
parent b3b8e81190
commit 9a1251875f
5 changed files with 191 additions and 71 deletions

View File

@ -1,5 +1,6 @@
//! A singlethreaded QEMU fuzzer that can auto-restart. //! A singlethreaded QEMU fuzzer that can auto-restart.
use libafl_qemu::QemuClockObserver;
use libafl::feedbacks::Feedback; use libafl::feedbacks::Feedback;
use crate::worst::HitImprovingFeedback; use crate::worst::HitImprovingFeedback;
use crate::worst::HitFeedback; use crate::worst::HitFeedback;
@ -152,7 +153,7 @@ pub fn main() {
} }
} }
let mut crashes = out_dir.clone(); let mut crashes = out_dir.clone();
crashes.push("crashes"); crashes.push("wcets");
out_dir.push("queue"); out_dir.push("queue");
let in_dir = PathBuf::from(res.value_of("in").unwrap().to_string()); let in_dir = PathBuf::from(res.value_of("in").unwrap().to_string());
@ -292,6 +293,7 @@ fn fuzz(
// Create an observation channel to keep track of the execution time // Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time"); let time_observer = TimeObserver::new("time");
let clock_observer = QemuClockObserver::default();
// Create an observation channel using cmplog map // Create an observation channel using cmplog map
let cmplog_observer = CmpLogObserver::new("cmplog", unsafe { &mut cmplog::CMPLOG_MAP }, true); let cmplog_observer = CmpLogObserver::new("cmplog", unsafe { &mut cmplog::CMPLOG_MAP }, true);
@ -387,7 +389,7 @@ fn fuzz(
//QemuAsanHelper::new(), //QemuAsanHelper::new(),
QemuSysSnapshotHelper::new() QemuSysSnapshotHelper::new()
), ),
tuple_list!(edges_observer, time_observer), tuple_list!(edges_observer, time_observer, clock_observer),
&mut fuzzer, &mut fuzzer,
&mut state, &mut state,
&mut mgr, &mut mgr,

View File

@ -1,3 +1,4 @@
#![feature(iter_advance_by)]
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
pub mod fuzzer; pub mod fuzzer;
pub mod showmap; pub mod showmap;

View File

@ -1,5 +1,12 @@
//! A singlethreaded QEMU fuzzer that can auto-restart. //! A singlethreaded QEMU fuzzer that can auto-restart.
use crate::worst::DumpMapFeedback;
use crate::worst::DummyFeedback;
use libafl::corpus::Corpus;
use libafl::state::HasCorpus;
use libafl::Fuzzer;
use libafl::mutators::BitFlipMutator;
use libafl::stages::StdMutationalStage;
use libafl_qemu::QemuInstrumentationFilter; use libafl_qemu::QemuInstrumentationFilter;
use crate::system_trace::QemuSystemStateHelper; use crate::system_trace::QemuSystemStateHelper;
use libafl::feedbacks::CrashFeedback; use libafl::feedbacks::CrashFeedback;
@ -258,7 +265,7 @@ fn fuzz(
let feedback = DumpMapFeedback::with_dump(dump_edges); let feedback = DumpMapFeedback::with_dump(dump_edges);
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not
let objective = QemuClockIncreaseFeedback::new(); let objective = DummyFeedback::new(false);
// create a State from scratch // create a State from scratch
let mut state = StdState::new( let mut state = StdState::new(
@ -330,67 +337,28 @@ fn fuzz(
true => seed_dir.clone().read_dir().expect("Directory not a directory?").next().expect("Directory empty?").expect("File not in directory?").path(), true => seed_dir.clone().read_dir().expect("Directory not a directory?").next().expect("Directory empty?").expect("File not in directory?").path(),
false => seed_dir.clone() false => seed_dir.clone()
}; };
// let secondinput = match seed_dir.clone().is_dir() {
// true => {
// let mut a = seed_dir.clone().read_dir().expect("Directory not a directory?");
// a.advance_by(1);
// a.next().unwrap().expect("File not in directory?").path()
// },
// false => seed_dir.clone()
// };
fuzzer.evaluate_input(&mut state, &mut executor, &mut mgr, Input::from_file(&firstinput).expect("Could not load file")).expect("Evaluation failed"); fuzzer.evaluate_input(&mut state, &mut executor, &mut mgr, Input::from_file(&firstinput).expect("Could not load file")).expect("Evaluation failed");
// fuzzer.evaluate_input(&mut state, &mut executor, &mut mgr, Input::from_file(&secondinput).expect("Could not load file")).expect("Evaluation failed");
// println!("Nach Eval");
// 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);
// return;
// });
// println!("We imported {} inputs from disk.", state.corpus().count());
// }
// fuzzer
// .fuzz_one(&mut tuple_list!(StdMutationalStage::new(BitFlipMutator::new())), &mut executor, &mut state, &mut mgr)
// .expect("Error in the fuzzing loop");
return Ok(()); return Ok(());
} }
//=========================== Debugging Feedback
/// A [`Feedback`] meant to dump the edgemap for debugging.
#[derive(Debug)]
pub struct DumpMapFeedback {
dumpfile: Option<PathBuf>
}
impl<I, S> Feedback<I, S> for DumpMapFeedback
where
I: Input,
S: HasClientPerfMonitor,
{
fn is_interesting<EM, OT>(
&mut self,
_state: &mut S,
_manager: &mut EM,
_input: &I,
_observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<I>,
OT: ObserversTuple<I, S>,
{
let observer = _observers.match_name::<HitcountsMapObserver<VariableMapObserver<u8>>>("edges")
.expect("HitcountsMapObserver not found");
match &self.dumpfile {
Some(s) => {
fs::write(s,ron::to_string(&observer.edgemap).expect("Error serializing hashmap")).expect("Can not dump to file");
self.dumpfile = None
},
None => println!("{:#?}",observer.edgemap),
};
Ok(true)
}
}
impl Named for DumpMapFeedback {
#[inline]
fn name(&self) -> &str {
"HitFeedback"
}
}
impl DumpMapFeedback {
/// Creates a new [`HitFeedback`]
#[must_use]
pub fn new() -> Self {
Self {dumpfile: None}
}
pub fn with_dump(dumpfile: Option<PathBuf>) -> Self {
Self {dumpfile: dumpfile}
}
}
impl Default for DumpMapFeedback {
fn default() -> Self {
Self::new()
}
}

View File

@ -1,3 +1,5 @@
use std::path::PathBuf;
use std::fs;
use libafl::observers::VariableMapObserver; use libafl::observers::VariableMapObserver;
use hashbrown::{HashMap}; use hashbrown::{HashMap};
use libafl::observers::ObserversTuple; use libafl::observers::ObserversTuple;
@ -182,7 +184,8 @@ where
} }
} }
let mean_sum_of_squares = (sum_of_square_difference as f64) / (self.target_map.len() as f64); let mean_sum_of_squares = (sum_of_square_difference as f64) / (self.target_map.len() as f64);
let hit_target = mean_sum_of_squares <= 1.0; let hit_target = mean_sum_of_squares <= self.target_msd;
eprintln!("hit target: {} {} {:?}",hit_target,mean_sum_of_squares, _input);
if hit_target { if hit_target {
Ok(true) Ok(true)
} else { } else {
@ -312,7 +315,7 @@ where
} }
let mean_sum_of_squares = (sum_of_square_difference as f64) / (self.target_map.len() as f64); let mean_sum_of_squares = (sum_of_square_difference as f64) / (self.target_map.len() as f64);
let hit_target = mean_sum_of_squares <= self.best_msd; let hit_target = mean_sum_of_squares <= self.best_msd;
eprintln!("in worst, {}",hit_target); eprintln!("improving: {}",hit_target);
if hit_target { if hit_target {
self.best_msd = mean_sum_of_squares; self.best_msd = mean_sum_of_squares;
Ok(true) Ok(true)
@ -341,4 +344,115 @@ impl Default for HitImprovingFeedback {
fn default() -> Self { fn default() -> Self {
Self::new(HashMap::new()) Self::new(HashMap::new())
} }
}
//=========================== Debugging Feedback
/// A [`Feedback`] meant to dump the edgemap for debugging.
#[derive(Debug)]
pub struct DumpMapFeedback {
dumpfile: Option<PathBuf>
}
impl<I, S> Feedback<I, S> for DumpMapFeedback
where
I: Input,
S: HasClientPerfMonitor,
{
fn is_interesting<EM, OT>(
&mut self,
_state: &mut S,
_manager: &mut EM,
_input: &I,
_observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<I>,
OT: ObserversTuple<I, S>,
{
let observer = _observers.match_name::<HitcountsMapObserver<VariableMapObserver<u8>>>("edges")
.expect("HitcountsMapObserver not found");
match &self.dumpfile {
Some(s) => {
fs::write(s,ron::to_string(&observer.edgemap).expect("Error serializing hashmap")).expect("Can not dump to file");
self.dumpfile = None
},
None => ()//println!("{:#?}",observer.edgemap),
};
Ok(true)
}
}
impl Named for DumpMapFeedback {
#[inline]
fn name(&self) -> &str {
"HitFeedback"
}
}
impl DumpMapFeedback {
/// Creates a new [`HitFeedback`]
#[must_use]
pub fn new() -> Self {
Self {dumpfile: None}
}
pub fn with_dump(dumpfile: Option<PathBuf>) -> Self {
Self {dumpfile: dumpfile}
}
}
impl Default for DumpMapFeedback {
fn default() -> Self {
Self::new()
}
}
//=========================== Debugging Feedback
/// A [`Feedback`] meant to dump the edgemap for debugging.
#[derive(Debug)]
pub struct DummyFeedback {
response: bool
}
impl<I, S> Feedback<I, S> for DummyFeedback
where
I: Input,
S: HasClientPerfMonitor,
{
fn is_interesting<EM, OT>(
&mut self,
_state: &mut S,
_manager: &mut EM,
_input: &I,
_observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<I>,
OT: ObserversTuple<I, S>,
{
eprintln!("Input was: {:?}",_input);
Ok(self.response)
}
}
impl Named for DummyFeedback {
#[inline]
fn name(&self) -> &str {
"DummyFeedback"
}
}
impl DummyFeedback {
/// Creates a new [`HitFeedback`]
#[must_use]
pub fn new(response: bool) -> Self {
Self {response: response}
}
}
impl Default for DummyFeedback {
fn default() -> Self {
Self::new(true)
}
} }

View File

@ -28,6 +28,16 @@ use libafl::events::EventFirer;
use libafl::state::HasClientPerfMonitor; use libafl::state::HasClientPerfMonitor;
use libafl::inputs::Input; use libafl::inputs::Input;
use libafl::feedbacks::Feedback; use libafl::feedbacks::Feedback;
use libafl::SerdeAny;
use libafl::state::HasMetadata;
use libafl::corpus::testcase::Testcase;
//========== Metadata
#[derive(Debug, Serialize, Deserialize, SerdeAny)]
pub struct QemuIcountMetadata {
runtime: i64,
}
// libafl::impl_serdeany!(QemuIcountMetadata);
//========== Observer //========== Observer
@ -55,7 +65,11 @@ impl QemuClockObserver {
} }
} }
impl<I, S> Observer<I, S> for QemuClockObserver { impl<I, S> Observer<I, S> for QemuClockObserver
where
I: Input,
S: HasMetadata,
{
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
self.last_runtime=0; self.last_runtime=0;
Ok(()) Ok(())
@ -63,6 +77,12 @@ impl<I, S> Observer<I, S> for QemuClockObserver {
fn post_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { fn post_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
unsafe { self.last_runtime = emu::libafl_get_clock() }; unsafe { self.last_runtime = emu::libafl_get_clock() };
// if !_state.has_metadata::<QemuIcountMetadata>() {
// _state.add_metadata(QemuIcountMetadata{runtime: self.last_runtime()});
// println!("Added Metadata");
// } else {
// println!("Found Metadata");
// }
println!("Observer Clock: {}",self.last_runtime()); println!("Observer Clock: {}",self.last_runtime());
Ok(()) Ok(())
} }
@ -84,12 +104,13 @@ impl Default for QemuClockObserver {
} }
} }
//========== Observer //========== Feedback
/// A [`Feedback`] rewarding increasing the execution cycles on Qemu. /// A [`Feedback`] rewarding increasing the execution cycles on Qemu.
#[derive(Debug)] #[derive(Debug)]
pub struct QemuClockIncreaseFeedback { pub struct QemuClockIncreaseFeedback {
maximum: i64 maximum: i64,
last_runtime: i64,
} }
impl<I, S> Feedback<I, S> for QemuClockIncreaseFeedback impl<I, S> Feedback<I, S> for QemuClockIncreaseFeedback
@ -111,12 +132,26 @@ where
{ {
let observer = _observers.match_name::<QemuClockObserver>("clock") let observer = _observers.match_name::<QemuClockObserver>("clock")
.expect("QemuClockObserver not found"); .expect("QemuClockObserver not found");
if observer.last_runtime() >= self.maximum { if observer.last_runtime() > self.maximum {
self.maximum = observer.last_runtime(); self.maximum = observer.last_runtime();
return Ok(true); return Ok(true);
} }
Ok(false) Ok(false)
} }
/// Append to the testcase the generated metadata in case of a new corpus item
#[inline]
fn append_metadata(&mut self, _state: &mut S, testcase: &mut Testcase<I>) -> Result<(), Error> {
testcase.metadata_mut().insert(QemuIcountMetadata{runtime: self.last_runtime});
Ok(())
}
/// Discard the stored metadata in case that the testcase is not added to the corpus
#[inline]
fn discard_metadata(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
Ok(())
}
} }
impl Named for QemuClockIncreaseFeedback { impl Named for QemuClockIncreaseFeedback {
@ -130,7 +165,7 @@ impl QemuClockIncreaseFeedback {
/// Creates a new [`HitFeedback`] /// Creates a new [`HitFeedback`]
#[must_use] #[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self {maximum: 0} Self {maximum: 0, last_runtime: 0}
} }
} }