diff --git a/fuzzers/wcet_qemu_sys/src/fuzzer.rs b/fuzzers/wcet_qemu_sys/src/fuzzer.rs index a6b95f8fde..f175e02894 100644 --- a/fuzzers/wcet_qemu_sys/src/fuzzer.rs +++ b/fuzzers/wcet_qemu_sys/src/fuzzer.rs @@ -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(); diff --git a/fuzzers/wcet_qemu_sys/src/showmap.rs b/fuzzers/wcet_qemu_sys/src/showmap.rs index 13153a9e0d..06ed342c7d 100644 --- a/fuzzers/wcet_qemu_sys/src/showmap.rs +++ b/fuzzers/wcet_qemu_sys/src/showmap.rs @@ -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, diff --git a/libafl_qemu/src/clock.rs b/libafl_qemu/src/clock.rs new file mode 100644 index 0000000000..66a316f1e9 --- /dev/null +++ b/libafl_qemu/src/clock.rs @@ -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 Observer 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 Feedback for QemuClockIncreaseFeedback +where + I: Input, + S: HasClientPerfMonitor, +{ + fn is_interesting( + &mut self, + _state: &mut S, + _manager: &mut EM, + _input: &I, + _observers: &OT, + _exit_kind: &ExitKind, + ) -> Result + where + EM: EventFirer, + OT: ObserversTuple, + { + let observer = _observers.match_name::("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() + } +} \ No newline at end of file diff --git a/libafl_qemu/src/emu.rs b/libafl_qemu/src/emu.rs index 04e7248056..532766f483 100644 --- a/libafl_qemu/src/emu.rs +++ b/libafl_qemu/src/emu.rs @@ -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")] diff --git a/libafl_qemu/src/lib.rs b/libafl_qemu/src/lib.rs index e7bbc3aaf3..66d7ca71db 100644 --- a/libafl_qemu/src/lib.rs +++ b/libafl_qemu/src/lib.rs @@ -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")]