Various improvements
Replace TimeObserver with ClockObserver Add a Maximization Scheduler for Clocks Factor out icount Metadata from Feedback Allow Breakpoint removal in systemmode
This commit is contained in:
parent
2ead941419
commit
06d382bff8
@ -1,6 +1,9 @@
|
||||
//! A singlethreaded QEMU fuzzer that can auto-restart.
|
||||
|
||||
use libafl_qemu::QemuClockObserver;
|
||||
use libafl::mutators::ByteFlipMutator;
|
||||
use libafl::mutators::BitFlipMutator;
|
||||
use crate::worst::LenTimeMaximizerCorpusScheduler;
|
||||
use libafl::corpus::MinimizerCorpusScheduler;
|
||||
use hashbrown::HashMap;
|
||||
use libafl::events::SimpleEventManager;
|
||||
use clap::{App, Arg};
|
||||
@ -57,6 +60,10 @@ use libafl_qemu::{
|
||||
filter_qemu_args,
|
||||
snapshot_sys::QemuSysSnapshotHelper,
|
||||
QemuExecutor,
|
||||
clock,
|
||||
QemuClockObserver,
|
||||
clock::ClockFeedback,
|
||||
clock::QemuClockIncreaseFeedback
|
||||
};
|
||||
use crate::worst::{HitFeedback,HitcountsMapObserver,HitImprovingFeedback};
|
||||
|
||||
@ -283,7 +290,7 @@ fn fuzz(
|
||||
HitcountsMapObserver::new(VariableMapObserver::new("edges", edges, edges_counter));
|
||||
|
||||
// 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
|
||||
@ -304,7 +311,9 @@ fn fuzz(
|
||||
};
|
||||
let feedback = feedback_or!(
|
||||
MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false),
|
||||
HitImprovingFeedback::new(target_map.clone())
|
||||
HitImprovingFeedback::new(target_map.clone()),
|
||||
QemuClockIncreaseFeedback::default(),
|
||||
ClockFeedback::new_with_observer(&clock_observer)
|
||||
);
|
||||
// let feedback = feedback_or!(
|
||||
// // New maximization map feedback linked to the edges observer and the feedback state
|
||||
@ -329,7 +338,7 @@ fn fuzz(
|
||||
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),
|
||||
tuple_list!(feedback_state,clock::MaxIcountMetadata::default()),
|
||||
)
|
||||
};
|
||||
|
||||
@ -380,7 +389,7 @@ fn fuzz(
|
||||
//QemuAsanHelper::new(),
|
||||
QemuSysSnapshotHelper::new()
|
||||
),
|
||||
tuple_list!(edges_observer, time_observer, clock_observer),
|
||||
tuple_list!(edges_observer, clock_observer),
|
||||
&mut fuzzer,
|
||||
&mut state,
|
||||
&mut mgr,
|
||||
|
@ -1,3 +1,8 @@
|
||||
use libafl::feedbacks::MapIndexesMetadata;
|
||||
use libafl::corpus::Testcase;
|
||||
use libafl::corpus::FavFactor;
|
||||
use core::marker::PhantomData;
|
||||
use libafl::corpus::MinimizerCorpusScheduler;
|
||||
use std::path::PathBuf;
|
||||
use std::fs;
|
||||
use libafl::observers::VariableMapObserver;
|
||||
@ -185,7 +190,7 @@ where
|
||||
}
|
||||
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.target_msd;
|
||||
eprintln!("hit target: {} {} {:?}",hit_target,mean_sum_of_squares, _input);
|
||||
// eprintln!("hit target: {} {} {:?}",hit_target,mean_sum_of_squares, _input);
|
||||
if hit_target {
|
||||
Ok(true)
|
||||
} else {
|
||||
@ -314,9 +319,10 @@ where
|
||||
}
|
||||
}
|
||||
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;
|
||||
eprintln!("improving: {}",hit_target);
|
||||
let hit_target = mean_sum_of_squares < self.best_msd;
|
||||
// eprintln!("improving: {}",hit_target);
|
||||
if hit_target {
|
||||
// println!("Hit Improving: {}",mean_sum_of_squares);
|
||||
self.best_msd = mean_sum_of_squares;
|
||||
Ok(true)
|
||||
} else {
|
||||
@ -408,7 +414,7 @@ impl Default for DumpMapFeedback {
|
||||
}
|
||||
|
||||
//=========================== Debugging Feedback
|
||||
/// A [`Feedback`] meant to dump the edgemap for debugging.
|
||||
/// A NoOp [`Feedback`] with fixed response.
|
||||
#[derive(Debug)]
|
||||
pub struct DummyFeedback {
|
||||
response: bool
|
||||
@ -456,3 +462,27 @@ impl Default for DummyFeedback {
|
||||
Self::new(true)
|
||||
}
|
||||
}
|
||||
|
||||
pub type LenTimeMaximizerCorpusScheduler<CS, I, S> =
|
||||
MinimizerCorpusScheduler<CS, MaxLenTimeFavFactor<I>, I, MapIndexesMetadata, S>;
|
||||
|
||||
/// Multiply the testcase size with the execution time.
|
||||
/// This favors small and quick testcases.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MaxLenTimeFavFactor<I>
|
||||
where
|
||||
I: Input + HasLen,
|
||||
{
|
||||
phantom: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<I> FavFactor<I> for MaxLenTimeFavFactor<I>
|
||||
where
|
||||
I: Input + HasLen,
|
||||
{
|
||||
fn compute(entry: &mut Testcase<I>) -> Result<u64, Error> {
|
||||
// TODO maybe enforce entry.exec_time().is_some()
|
||||
let execs_per_hour = (3600.0/entry.exec_time().expect("testcase.exec_time is needed for scheduler").as_secs_f64()) as u64;
|
||||
Ok(execs_per_hour)
|
||||
}
|
||||
}
|
@ -31,21 +31,66 @@ use libafl::feedbacks::Feedback;
|
||||
use libafl::SerdeAny;
|
||||
use libafl::state::HasMetadata;
|
||||
use libafl::corpus::testcase::Testcase;
|
||||
use core::{fmt::Debug, time::Duration};
|
||||
use libafl::feedbacks::FeedbackState;
|
||||
use libafl::state::HasFeedbackStates;
|
||||
use libafl::bolts::tuples::MatchName;
|
||||
|
||||
//========== Metadata
|
||||
#[derive(Debug, Serialize, Deserialize, SerdeAny)]
|
||||
pub struct QemuIcountMetadata {
|
||||
runtime: i64,
|
||||
runtime: u64,
|
||||
}
|
||||
// libafl::impl_serdeany!(QemuIcountMetadata);
|
||||
|
||||
/// Metadata for [`QemuClockIncreaseFeedback`]
|
||||
#[derive(Debug, Serialize, Deserialize, SerdeAny)]
|
||||
pub struct MaxIcountMetadata {
|
||||
pub max_icount_seen: u64,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
impl FeedbackState for MaxIcountMetadata
|
||||
{
|
||||
fn reset(&mut self) -> Result<(), Error> {
|
||||
self.max_icount_seen = 0;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Named for MaxIcountMetadata
|
||||
{
|
||||
#[inline]
|
||||
fn name(&self) -> &str {
|
||||
self.name.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl MaxIcountMetadata
|
||||
{
|
||||
/// Create new `MaxIcountMetadata`
|
||||
#[must_use]
|
||||
pub fn new(name: &'static str) -> Self {
|
||||
Self {
|
||||
max_icount_seen: 0,
|
||||
name: name.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for MaxIcountMetadata {
|
||||
fn default() -> Self {
|
||||
Self::new("MaxClock")
|
||||
}
|
||||
}
|
||||
|
||||
//========== Observer
|
||||
|
||||
/// A simple observer, just overlooking the runtime of the target.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct QemuClockObserver {
|
||||
name: String,
|
||||
last_runtime: i64,
|
||||
last_runtime: u64,
|
||||
}
|
||||
|
||||
impl QemuClockObserver {
|
||||
@ -60,7 +105,7 @@ impl QemuClockObserver {
|
||||
|
||||
/// Gets the runtime for the last execution of this target.
|
||||
#[must_use]
|
||||
pub fn last_runtime(&self) -> i64 {
|
||||
pub fn last_runtime(&self) -> u64 {
|
||||
self.last_runtime
|
||||
}
|
||||
}
|
||||
@ -83,7 +128,7 @@ where
|
||||
// } else {
|
||||
// println!("Found Metadata");
|
||||
// }
|
||||
println!("Observer Clock: {}",self.last_runtime());
|
||||
// println!("Observer Clock: {}",self.last_runtime());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -105,15 +150,16 @@ impl Default for QemuClockObserver {
|
||||
}
|
||||
|
||||
//========== Feedback
|
||||
|
||||
/// A [`Feedback`] rewarding increasing the execution cycles on Qemu.
|
||||
#[derive(Debug)]
|
||||
pub struct QemuClockIncreaseFeedback {
|
||||
maximum: i64,
|
||||
last_runtime: i64,
|
||||
/// Nop feedback that annotates execution time in the new testcase, if any
|
||||
/// for this Feedback, the testcase is never interesting (use with an OR)
|
||||
/// It decides, if the given [`ClockObserver`] value of a run is interesting.
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct ClockFeedback {
|
||||
exec_time: Option<u64>,
|
||||
name: String,
|
||||
}
|
||||
|
||||
impl<I, S> Feedback<I, S> for QemuClockIncreaseFeedback
|
||||
impl<I, S> Feedback<I, S> for ClockFeedback
|
||||
where
|
||||
I: Input,
|
||||
S: HasClientPerfMonitor,
|
||||
@ -123,6 +169,81 @@ where
|
||||
_state: &mut S,
|
||||
_manager: &mut EM,
|
||||
_input: &I,
|
||||
observers: &OT,
|
||||
_exit_kind: &ExitKind,
|
||||
) -> Result<bool, Error>
|
||||
where
|
||||
EM: EventFirer<I>,
|
||||
OT: ObserversTuple<I, S>,
|
||||
{
|
||||
// TODO Replace with match_name_type when stable
|
||||
let observer = observers.match_name::<QemuClockObserver>(self.name()).unwrap();
|
||||
self.exec_time = Some(observer.last_runtime());
|
||||
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.exec_time_mut() = match self.exec_time {
|
||||
Some(s) => Some(Duration::new(0,360*s as u32)),
|
||||
None => None,
|
||||
};
|
||||
self.exec_time = None;
|
||||
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> {
|
||||
self.exec_time = None;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Named for ClockFeedback {
|
||||
#[inline]
|
||||
fn name(&self) -> &str {
|
||||
self.name.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl ClockFeedback {
|
||||
/// Creates a new [`ClockFeedback`], deciding if the value of a [`TimeObserver`] with the given `name` of a run is interesting.
|
||||
#[must_use]
|
||||
pub fn new(name: &'static str) -> Self {
|
||||
Self {
|
||||
exec_time: None,
|
||||
name: name.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new [`ClockFeedback`], deciding if the given [`TimeObserver`] value of a run is interesting.
|
||||
#[must_use]
|
||||
pub fn new_with_observer(observer: &QemuClockObserver) -> Self {
|
||||
Self {
|
||||
exec_time: None,
|
||||
name: observer.name().to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`Feedback`] rewarding increasing the execution cycles on Qemu.
|
||||
#[derive(Debug)]
|
||||
pub struct QemuClockIncreaseFeedback {
|
||||
name: String,
|
||||
}
|
||||
|
||||
impl<I, S> Feedback<I, S> for QemuClockIncreaseFeedback
|
||||
where
|
||||
I: Input,
|
||||
S: HasFeedbackStates + HasClientPerfMonitor,
|
||||
{
|
||||
fn is_interesting<EM, OT>(
|
||||
&mut self,
|
||||
state: &mut S,
|
||||
_manager: &mut EM,
|
||||
_input: &I,
|
||||
_observers: &OT,
|
||||
_exit_kind: &ExitKind,
|
||||
) -> Result<bool, Error>
|
||||
@ -132,8 +253,13 @@ where
|
||||
{
|
||||
let observer = _observers.match_name::<QemuClockObserver>("clock")
|
||||
.expect("QemuClockObserver not found");
|
||||
if observer.last_runtime() > self.maximum {
|
||||
self.maximum = observer.last_runtime();
|
||||
let clock_state = state
|
||||
.feedback_states_mut()
|
||||
.match_name_mut::<MaxIcountMetadata>(&self.name)
|
||||
.unwrap();
|
||||
if observer.last_runtime() > clock_state.max_icount_seen {
|
||||
// println!("Clock improving {}",observer.last_runtime());
|
||||
clock_state.max_icount_seen = observer.last_runtime();
|
||||
return Ok(true);
|
||||
}
|
||||
Ok(false)
|
||||
@ -142,7 +268,7 @@ where
|
||||
/// 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});
|
||||
// testcase.metadata_mut().insert(QemuIcountMetadata{runtime: self.last_runtime});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -157,20 +283,20 @@ where
|
||||
impl Named for QemuClockIncreaseFeedback {
|
||||
#[inline]
|
||||
fn name(&self) -> &str {
|
||||
"QemuClockFeedback"
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
|
||||
impl QemuClockIncreaseFeedback {
|
||||
/// Creates a new [`HitFeedback`]
|
||||
#[must_use]
|
||||
pub fn new() -> Self {
|
||||
Self {maximum: 0, last_runtime: 0}
|
||||
pub fn new(name: &'static str) -> Self {
|
||||
Self {name: String::from(name)}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for QemuClockIncreaseFeedback {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
Self::new("MaxClock")
|
||||
}
|
||||
}
|
@ -183,6 +183,8 @@ extern "C" {
|
||||
fn libafl_qemu_set_breakpoint(addr: u64) -> i32;
|
||||
#[cfg(feature = "systemmode")]
|
||||
fn libafl_qemu_set_native_breakpoint(addr: u64) -> i32;
|
||||
#[cfg(feature = "systemmode")]
|
||||
fn libafl_qemu_remove_native_breakpoint(addr: u64) -> i32;
|
||||
fn libafl_qemu_remove_breakpoint(addr: u64) -> i32;
|
||||
fn libafl_qemu_set_hook(addr: u64, callback: extern "C" fn(u64), val: u64) -> i32;
|
||||
fn libafl_qemu_remove_hook(addr: u64) -> i32;
|
||||
@ -200,7 +202,7 @@ extern "C" {
|
||||
#[cfg(feature = "systemmode")]
|
||||
fn libafl_snapshot_load(name: *const c_char) -> i32;
|
||||
#[cfg(feature = "systemmode")]
|
||||
pub fn libafl_get_clock() -> i64;
|
||||
pub fn libafl_get_clock() -> u64;
|
||||
|
||||
fn strlen(s: *const u8) -> usize;
|
||||
|
||||
@ -438,6 +440,9 @@ impl Emulator {
|
||||
|
||||
pub fn remove_breakpoint(&self, addr: u64) {
|
||||
unsafe {
|
||||
#[cfg(feature = "systemmode")]
|
||||
libafl_qemu_remove_native_breakpoint(addr);
|
||||
#[cfg(not(feature = "systemmode"))]
|
||||
libafl_qemu_remove_breakpoint(addr);
|
||||
}
|
||||
}
|
||||
@ -682,7 +687,7 @@ impl Emulator {
|
||||
}
|
||||
|
||||
#[cfg(feature = "systemmode")]
|
||||
pub fn get_ticks(&self) -> i64{
|
||||
pub fn get_ticks(&self) -> u64{
|
||||
return unsafe { libafl_get_clock() };
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user