diff --git a/libafl_qemu/src/asan.rs b/libafl_qemu/src/asan.rs index 39fbc5cf0a..ca53643ce8 100644 --- a/libafl_qemu/src/asan.rs +++ b/libafl_qemu/src/asan.rs @@ -6,7 +6,7 @@ use std::{ sync::Mutex, }; -use libafl::{inputs::UsesInput, state::HasMetadata}; +use libafl::{executors::ExitKind, inputs::UsesInput, state::HasMetadata}; use libc::{ c_void, MAP_ANON, MAP_FAILED, MAP_FIXED, MAP_NORESERVE, MAP_PRIVATE, PROT_READ, PROT_WRITE, }; @@ -53,7 +53,7 @@ pub enum QasanAction { SwapState, } -#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy)] +#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, PartialEq)] #[repr(i8)] pub enum PoisonKind { Valid = 0, @@ -79,6 +79,13 @@ pub enum PoisonKind { HeapFreed = -3, // 0xfd } +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum AsanRollback { + Ok, + HasLeaks, +} + +#[derive(Debug, Clone, PartialEq)] pub enum AsanError { Read(GuestAddr, usize), Write(GuestAddr, usize), @@ -343,7 +350,7 @@ impl AsanGiovese { } } - pub fn report_and_crash(&mut self, emu: &Emulator, error: AsanError) { + pub fn report_or_crash(&mut self, emu: &Emulator, error: AsanError) { if let Some(cb) = self.error_callback.as_mut() { (cb)(emu, error); } else { @@ -351,6 +358,12 @@ impl AsanGiovese { } } + pub fn report(&mut self, emu: &Emulator, error: AsanError) { + if let Some(cb) = self.error_callback.as_mut() { + (cb)(emu, error); + } + } + pub fn alloc_insert(&mut self, start: GuestAddr, end: GuestAddr) { self.alloc_tree.lock().unwrap().insert(start..end, ()); } @@ -390,7 +403,7 @@ impl AsanGiovese { } } - pub fn rollback(&mut self, emu: &Emulator, detect_leaks: bool) { + pub fn rollback(&mut self, emu: &Emulator, detect_leaks: bool) -> AsanRollback { let mut leaks = vec![]; { @@ -423,9 +436,17 @@ impl AsanGiovese { set.clear(); } + let ret = if leaks.is_empty() { + AsanRollback::Ok + } else { + AsanRollback::HasLeaks + }; + for interval in leaks { - self.report_and_crash(emu, AsanError::MemLeak(interval)); + self.report(emu, AsanError::MemLeak(interval)); } + + ret } } @@ -563,12 +584,12 @@ impl QemuAsanHelper { if ck.start != addr { // Free not the start of the chunk self.rt - .report_and_crash(emulator, AsanError::BadFree(addr, Some(ck))); + .report_or_crash(emulator, AsanError::BadFree(addr, Some(ck))); } } else { // Free of wild ptr self.rt - .report_and_crash(emulator, AsanError::BadFree(addr, None)); + .report_or_crash(emulator, AsanError::BadFree(addr, None)); } } @@ -580,67 +601,63 @@ impl QemuAsanHelper { pub fn read_1(&mut self, emulator: &Emulator, addr: GuestAddr) { if self.enabled() && AsanGiovese::is_invalid_access_1(emulator, addr) { - self.rt.report_and_crash(emulator, AsanError::Read(addr, 1)); + self.rt.report_or_crash(emulator, AsanError::Read(addr, 1)); } } pub fn read_2(&mut self, emulator: &Emulator, addr: GuestAddr) { if self.enabled() && AsanGiovese::is_invalid_access_2(emulator, addr) { - self.rt.report_and_crash(emulator, AsanError::Read(addr, 2)); + self.rt.report_or_crash(emulator, AsanError::Read(addr, 2)); } } pub fn read_4(&mut self, emulator: &Emulator, addr: GuestAddr) { if self.enabled() && AsanGiovese::is_invalid_access_4(emulator, addr) { - self.rt.report_and_crash(emulator, AsanError::Read(addr, 4)); + self.rt.report_or_crash(emulator, AsanError::Read(addr, 4)); } } pub fn read_8(&mut self, emulator: &Emulator, addr: GuestAddr) { if self.enabled() && AsanGiovese::is_invalid_access_8(emulator, addr) { - self.rt.report_and_crash(emulator, AsanError::Read(addr, 8)); + self.rt.report_or_crash(emulator, AsanError::Read(addr, 8)); } } pub fn read_n(&mut self, emulator: &Emulator, addr: GuestAddr, size: usize) { if self.enabled() && AsanGiovese::is_invalid_access(emulator, addr, size) { self.rt - .report_and_crash(emulator, AsanError::Read(addr, size)); + .report_or_crash(emulator, AsanError::Read(addr, size)); } } pub fn write_1(&mut self, emulator: &Emulator, addr: GuestAddr) { if self.enabled() && AsanGiovese::is_invalid_access_1(emulator, addr) { - self.rt - .report_and_crash(emulator, AsanError::Write(addr, 1)); + self.rt.report_or_crash(emulator, AsanError::Write(addr, 1)); } } pub fn write_2(&mut self, emulator: &Emulator, addr: GuestAddr) { if self.enabled() && AsanGiovese::is_invalid_access_2(emulator, addr) { - self.rt - .report_and_crash(emulator, AsanError::Write(addr, 2)); + self.rt.report_or_crash(emulator, AsanError::Write(addr, 2)); } } pub fn write_4(&mut self, emulator: &Emulator, addr: GuestAddr) { if self.enabled() && AsanGiovese::is_invalid_access_4(emulator, addr) { - self.rt - .report_and_crash(emulator, AsanError::Write(addr, 4)); + self.rt.report_or_crash(emulator, AsanError::Write(addr, 4)); } } pub fn write_8(&mut self, emulator: &Emulator, addr: GuestAddr) { if self.enabled() && AsanGiovese::is_invalid_access_8(emulator, addr) { - self.rt - .report_and_crash(emulator, AsanError::Write(addr, 8)); + self.rt.report_or_crash(emulator, AsanError::Write(addr, 8)); } } pub fn write_n(&mut self, emulator: &Emulator, addr: GuestAddr, size: usize) { if self.enabled() && AsanGiovese::is_invalid_access(emulator, addr, size) { self.rt - .report_and_crash(emulator, AsanError::Write(addr, size)); + .report_or_crash(emulator, AsanError::Write(addr, size)); } } @@ -659,8 +676,8 @@ impl QemuAsanHelper { AsanGiovese::unpoison(emulator, addr, size); } - pub fn reset(&mut self, emulator: &Emulator) { - self.rt.rollback(emulator, self.detect_leaks); + pub fn reset(&mut self, emulator: &Emulator) -> AsanRollback { + self.rt.rollback(emulator, self.detect_leaks) } } @@ -713,8 +730,10 @@ where } } - fn post_exec(&mut self, emulator: &Emulator, _input: &S::Input) { - self.reset(emulator); + fn post_exec(&mut self, emulator: &Emulator, _input: &S::Input, exit_kind: &mut ExitKind) { + if self.reset(emulator) == AsanRollback::HasLeaks { + *exit_kind = ExitKind::Crash; + } } } diff --git a/libafl_qemu/src/drcov.rs b/libafl_qemu/src/drcov.rs index 81ef3e4199..d4b38498b8 100644 --- a/libafl_qemu/src/drcov.rs +++ b/libafl_qemu/src/drcov.rs @@ -1,7 +1,7 @@ use std::{path::PathBuf, sync::Mutex}; use hashbrown::{hash_map::Entry, HashMap}; -use libafl::{inputs::UsesInput, state::HasMetadata}; +use libafl::{executors::ExitKind, inputs::UsesInput, state::HasMetadata}; use libafl_targets::drcov::{DrCovBasicBlock, DrCovWriter}; use rangemap::RangeMap; use serde::{Deserialize, Serialize}; @@ -83,7 +83,7 @@ where fn pre_exec(&mut self, _emulator: &Emulator, _input: &S::Input) {} - fn post_exec(&mut self, emulator: &Emulator, _input: &S::Input) { + fn post_exec(&mut self, emulator: &Emulator, _input: &S::Input, _exit_kind: &mut ExitKind) { if self.full_trace { if DRCOV_IDS.lock().unwrap().as_ref().unwrap().len() > self.drcov_len { let mut drcov_vec = Vec::::new(); diff --git a/libafl_qemu/src/executor.rs b/libafl_qemu/src/executor.rs index 5583f89a1f..8f83d25335 100644 --- a/libafl_qemu/src/executor.rs +++ b/libafl_qemu/src/executor.rs @@ -117,9 +117,11 @@ where self.first_exec = false; } self.hooks.helpers_mut().pre_exec_all(&emu, input); - let r = self.inner.run_target(fuzzer, state, mgr, input); - self.hooks.helpers_mut().post_exec_all(&emu, input); - r + let mut exit_kind = self.inner.run_target(fuzzer, state, mgr, input)?; + self.hooks + .helpers_mut() + .post_exec_all(&emu, input, &mut exit_kind); + Ok(exit_kind) } } @@ -277,9 +279,11 @@ where self.first_exec = false; } self.hooks.helpers_mut().pre_exec_all(&emu, input); - let r = self.inner.run_target(fuzzer, state, mgr, input); - self.hooks.helpers_mut().post_exec_all(&emu, input); - r + let mut exit_kind = self.inner.run_target(fuzzer, state, mgr, input)?; + self.hooks + .helpers_mut() + .post_exec_all(&emu, input, &mut exit_kind); + Ok(exit_kind) } } diff --git a/libafl_qemu/src/helper.rs b/libafl_qemu/src/helper.rs index 80bb06fbfc..d579b635d2 100644 --- a/libafl_qemu/src/helper.rs +++ b/libafl_qemu/src/helper.rs @@ -1,6 +1,6 @@ use core::{fmt::Debug, ops::Range}; -use libafl::{bolts::tuples::MatchFirstType, inputs::UsesInput}; +use libafl::{bolts::tuples::MatchFirstType, executors::ExitKind, inputs::UsesInput}; use crate::{emu::Emulator, hooks::QemuHooks}; @@ -26,7 +26,7 @@ where fn pre_exec(&mut self, _emulator: &Emulator, _input: &S::Input) {} - fn post_exec(&mut self, _emulator: &Emulator, _input: &S::Input) {} + fn post_exec(&mut self, _emulator: &Emulator, _input: &S::Input, _exit_kind: &mut ExitKind) {} } pub trait QemuHelperTuple: MatchFirstType + Debug @@ -45,7 +45,7 @@ where fn pre_exec_all(&mut self, _emulator: &Emulator, input: &S::Input); - fn post_exec_all(&mut self, _emulator: &Emulator, input: &S::Input); + fn post_exec_all(&mut self, _emulator: &Emulator, input: &S::Input, _exit_kind: &mut ExitKind); } impl QemuHelperTuple for () @@ -68,7 +68,13 @@ where fn pre_exec_all(&mut self, _emulator: &Emulator, _input: &S::Input) {} - fn post_exec_all(&mut self, _emulator: &Emulator, _input: &S::Input) {} + fn post_exec_all( + &mut self, + _emulator: &Emulator, + _input: &S::Input, + _exit_kind: &mut ExitKind, + ) { + } } impl QemuHelperTuple for (Head, Tail) @@ -100,9 +106,9 @@ where self.1.pre_exec_all(emulator, input); } - fn post_exec_all(&mut self, emulator: &Emulator, input: &S::Input) { - self.0.post_exec(emulator, input); - self.1.post_exec_all(emulator, input); + fn post_exec_all(&mut self, emulator: &Emulator, input: &S::Input, exit_kind: &mut ExitKind) { + self.0.post_exec(emulator, input, exit_kind); + self.1.post_exec_all(emulator, input, exit_kind); } }