add QemuClockObserver

This commit is contained in:
Alwin Berger 2022-01-31 19:39:22 +01:00
parent ba85877ab4
commit b3b8e81190
5 changed files with 161 additions and 2 deletions

View File

@ -219,6 +219,7 @@ fn fuzz(
"-kernel", kernel.to_str().unwrap(),
"-serial", "stdio", "-nographic",
"-snapshot", "-drive", "if=none,format=qcow2,file=dummy.qcow2",
"-icount", "shift=auto,align=off,sleep=off",
"-S"
].iter().map(|x| x.to_string()).collect();
let env: Vec<(String, String)> = env::vars().collect();

View File

@ -43,6 +43,8 @@ use libafl_qemu::{
emu::Emulator, filter_qemu_args,
snapshot_sys::QemuSysSnapshotHelper,
elf::EasyElf,
clock,
clock::{QemuClockObserver,QemuClockIncreaseFeedback},
};
use crate::freertos;
@ -177,6 +179,7 @@ fn fuzz(
"-kernel", kernel.to_str().unwrap(),
"-serial", "stdio", "-nographic",
"-snapshot", "-drive", "if=none,format=qcow2,file=dummy.qcow2",
"-icount", "shift=auto,align=off,sleep=off",
"-S"
].iter().map(|x| x.to_string()).collect();
let emu = Emulator::new(&mut args, &mut env);
@ -248,11 +251,14 @@ fn fuzz(
let edges_observer =
HitcountsMapObserver::new(VariableMapObserver::new("edges", edges, edges_counter));
//========== Observe Execution Cycles
let clock_observer = QemuClockObserver::default();
//========= Feedback-Function evaluate the Maps. Need to dump it for debugging and check if it reaches targets.
let feedback = DumpMapFeedback::with_dump(dump_edges);
// A feedback to choose if an input is a solution or not
let objective = CrashFeedback::new();
let objective = QemuClockIncreaseFeedback::new();
// create a State from scratch
let mut state = StdState::new(
@ -315,7 +321,7 @@ fn fuzz(
QemuSysSnapshotHelper::new(),
QemuSystemStateHelper::with_instrumentation_filter(system_state_filter,curr_tcb_pointer.try_into().unwrap(),task_queue_addr.try_into().unwrap())
),
tuple_list!(edges_observer),
tuple_list!(edges_observer,clock_observer),
&mut fuzzer,
&mut state,
&mut mgr,

141
libafl_qemu/src/clock.rs Normal file
View File

@ -0,0 +1,141 @@
use hashbrown::{hash_map::Entry, HashMap};
use libafl::{
bolts::{
current_nanos,
rands::StdRand,
tuples::{tuple_list},
},
corpus::{QueueCorpusScheduler},
executors::{ExitKind},
fuzzer::{StdFuzzer},
inputs::{BytesInput, HasTargetBytes},
observers::{Observer,VariableMapObserver},
state::{StdState},
Error,
observers::ObserversTuple,
};
use serde::{Deserialize, Serialize};
use std::{cell::UnsafeCell, cmp::max};
use libafl::bolts::tuples::Named;
use crate::{
emu,
emu::Emulator,
executor::QemuExecutor,
helper::{QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
};
use libafl::events::EventFirer;
use libafl::state::HasClientPerfMonitor;
use libafl::inputs::Input;
use libafl::feedbacks::Feedback;
//========== Observer
/// A simple observer, just overlooking the runtime of the target.
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct QemuClockObserver {
name: String,
last_runtime: i64,
}
impl QemuClockObserver {
/// Creates a new [`QemuClockObserver`] with the given name.
#[must_use]
pub fn new(name: &'static str) -> Self {
Self {
name: name.to_string(),
last_runtime: 0,
}
}
/// Gets the runtime for the last execution of this target.
#[must_use]
pub fn last_runtime(&self) -> i64 {
self.last_runtime
}
}
impl<I, S> Observer<I, S> for QemuClockObserver {
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
self.last_runtime=0;
Ok(())
}
fn post_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
unsafe { self.last_runtime = emu::libafl_get_clock() };
println!("Observer Clock: {}",self.last_runtime());
Ok(())
}
}
impl Named for QemuClockObserver {
#[inline]
fn name(&self) -> &str {
&self.name
}
}
impl Default for QemuClockObserver {
fn default() -> Self {
Self {
name: String::from("clock"),
last_runtime: 0,
}
}
}
//========== Observer
/// A [`Feedback`] rewarding increasing the execution cycles on Qemu.
#[derive(Debug)]
pub struct QemuClockIncreaseFeedback {
maximum: i64
}
impl<I, S> Feedback<I, S> for QemuClockIncreaseFeedback
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::<QemuClockObserver>("clock")
.expect("QemuClockObserver not found");
if observer.last_runtime() >= self.maximum {
self.maximum = observer.last_runtime();
return Ok(true);
}
Ok(false)
}
}
impl Named for QemuClockIncreaseFeedback {
#[inline]
fn name(&self) -> &str {
"QemuClockFeedback"
}
}
impl QemuClockIncreaseFeedback {
/// Creates a new [`HitFeedback`]
#[must_use]
pub fn new() -> Self {
Self {maximum: 0}
}
}
impl Default for QemuClockIncreaseFeedback {
fn default() -> Self {
Self::new()
}
}

View File

@ -199,6 +199,8 @@ extern "C" {
fn libafl_snapshot_save(name: *const c_char) -> i32;
#[cfg(feature = "systemmode")]
fn libafl_snapshot_load(name: *const c_char) -> i32;
#[cfg(feature = "systemmode")]
pub fn libafl_get_clock() -> i64;
fn strlen(s: *const u8) -> usize;
@ -678,6 +680,11 @@ impl Emulator {
_ => true,
}
}
#[cfg(feature = "systemmode")]
pub fn get_ticks(&self) -> i64{
return unsafe { libafl_get_clock() };
}
}
#[cfg(feature = "python")]

View File

@ -43,6 +43,10 @@ pub use snapshot::QemuSnapshotHelper;
pub mod snapshot_sys;
#[cfg(all(target_os = "linux",feature = "systemmode"))]
pub use snapshot_sys::QemuSysSnapshotHelper;
#[cfg(all(target_os = "linux",feature = "systemmode"))]
pub mod clock;
#[cfg(all(target_os = "linux",feature = "systemmode"))]
pub use clock::QemuClockObserver;
#[cfg(target_os = "linux")]
pub mod asan;
#[cfg(target_os = "linux")]