QEMU: do not crash in helpers pre and post execs (#1065)

* QEMU: do not crash in helpers pre and post execs

* comma
This commit is contained in:
Andrea Fioraldi 2023-02-14 13:35:20 +01:00 committed by GitHub
parent 53dba5f49d
commit f8a4a020e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 69 additions and 40 deletions

View File

@ -6,7 +6,7 @@ use std::{
sync::Mutex, sync::Mutex,
}; };
use libafl::{inputs::UsesInput, state::HasMetadata}; use libafl::{executors::ExitKind, inputs::UsesInput, state::HasMetadata};
use libc::{ use libc::{
c_void, MAP_ANON, MAP_FAILED, MAP_FIXED, MAP_NORESERVE, MAP_PRIVATE, PROT_READ, PROT_WRITE, c_void, MAP_ANON, MAP_FAILED, MAP_FIXED, MAP_NORESERVE, MAP_PRIVATE, PROT_READ, PROT_WRITE,
}; };
@ -53,7 +53,7 @@ pub enum QasanAction {
SwapState, SwapState,
} }
#[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy)] #[derive(IntoPrimitive, TryFromPrimitive, Debug, Clone, Copy, PartialEq)]
#[repr(i8)] #[repr(i8)]
pub enum PoisonKind { pub enum PoisonKind {
Valid = 0, Valid = 0,
@ -79,6 +79,13 @@ pub enum PoisonKind {
HeapFreed = -3, // 0xfd HeapFreed = -3, // 0xfd
} }
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum AsanRollback {
Ok,
HasLeaks,
}
#[derive(Debug, Clone, PartialEq)]
pub enum AsanError { pub enum AsanError {
Read(GuestAddr, usize), Read(GuestAddr, usize),
Write(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() { if let Some(cb) = self.error_callback.as_mut() {
(cb)(emu, error); (cb)(emu, error);
} else { } 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) { pub fn alloc_insert(&mut self, start: GuestAddr, end: GuestAddr) {
self.alloc_tree.lock().unwrap().insert(start..end, ()); 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![]; let mut leaks = vec![];
{ {
@ -423,9 +436,17 @@ impl AsanGiovese {
set.clear(); set.clear();
} }
let ret = if leaks.is_empty() {
AsanRollback::Ok
} else {
AsanRollback::HasLeaks
};
for interval in leaks { 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 { if ck.start != addr {
// Free not the start of the chunk // Free not the start of the chunk
self.rt self.rt
.report_and_crash(emulator, AsanError::BadFree(addr, Some(ck))); .report_or_crash(emulator, AsanError::BadFree(addr, Some(ck)));
} }
} else { } else {
// Free of wild ptr // Free of wild ptr
self.rt 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) { pub fn read_1(&mut self, emulator: &Emulator, addr: GuestAddr) {
if self.enabled() && AsanGiovese::is_invalid_access_1(emulator, addr) { 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) { pub fn read_2(&mut self, emulator: &Emulator, addr: GuestAddr) {
if self.enabled() && AsanGiovese::is_invalid_access_2(emulator, addr) { 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) { pub fn read_4(&mut self, emulator: &Emulator, addr: GuestAddr) {
if self.enabled() && AsanGiovese::is_invalid_access_4(emulator, addr) { 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) { pub fn read_8(&mut self, emulator: &Emulator, addr: GuestAddr) {
if self.enabled() && AsanGiovese::is_invalid_access_8(emulator, addr) { 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) { pub fn read_n(&mut self, emulator: &Emulator, addr: GuestAddr, size: usize) {
if self.enabled() && AsanGiovese::is_invalid_access(emulator, addr, size) { if self.enabled() && AsanGiovese::is_invalid_access(emulator, addr, size) {
self.rt 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) { pub fn write_1(&mut self, emulator: &Emulator, addr: GuestAddr) {
if self.enabled() && AsanGiovese::is_invalid_access_1(emulator, addr) { if self.enabled() && AsanGiovese::is_invalid_access_1(emulator, addr) {
self.rt self.rt.report_or_crash(emulator, AsanError::Write(addr, 1));
.report_and_crash(emulator, AsanError::Write(addr, 1));
} }
} }
pub fn write_2(&mut self, emulator: &Emulator, addr: GuestAddr) { pub fn write_2(&mut self, emulator: &Emulator, addr: GuestAddr) {
if self.enabled() && AsanGiovese::is_invalid_access_2(emulator, addr) { if self.enabled() && AsanGiovese::is_invalid_access_2(emulator, addr) {
self.rt self.rt.report_or_crash(emulator, AsanError::Write(addr, 2));
.report_and_crash(emulator, AsanError::Write(addr, 2));
} }
} }
pub fn write_4(&mut self, emulator: &Emulator, addr: GuestAddr) { pub fn write_4(&mut self, emulator: &Emulator, addr: GuestAddr) {
if self.enabled() && AsanGiovese::is_invalid_access_4(emulator, addr) { if self.enabled() && AsanGiovese::is_invalid_access_4(emulator, addr) {
self.rt self.rt.report_or_crash(emulator, AsanError::Write(addr, 4));
.report_and_crash(emulator, AsanError::Write(addr, 4));
} }
} }
pub fn write_8(&mut self, emulator: &Emulator, addr: GuestAddr) { pub fn write_8(&mut self, emulator: &Emulator, addr: GuestAddr) {
if self.enabled() && AsanGiovese::is_invalid_access_8(emulator, addr) { if self.enabled() && AsanGiovese::is_invalid_access_8(emulator, addr) {
self.rt self.rt.report_or_crash(emulator, AsanError::Write(addr, 8));
.report_and_crash(emulator, AsanError::Write(addr, 8));
} }
} }
pub fn write_n(&mut self, emulator: &Emulator, addr: GuestAddr, size: usize) { pub fn write_n(&mut self, emulator: &Emulator, addr: GuestAddr, size: usize) {
if self.enabled() && AsanGiovese::is_invalid_access(emulator, addr, size) { if self.enabled() && AsanGiovese::is_invalid_access(emulator, addr, size) {
self.rt 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); AsanGiovese::unpoison(emulator, addr, size);
} }
pub fn reset(&mut self, emulator: &Emulator) { pub fn reset(&mut self, emulator: &Emulator) -> AsanRollback {
self.rt.rollback(emulator, self.detect_leaks); self.rt.rollback(emulator, self.detect_leaks)
} }
} }
@ -713,8 +730,10 @@ where
} }
} }
fn post_exec(&mut self, emulator: &Emulator, _input: &S::Input) { fn post_exec(&mut self, emulator: &Emulator, _input: &S::Input, exit_kind: &mut ExitKind) {
self.reset(emulator); if self.reset(emulator) == AsanRollback::HasLeaks {
*exit_kind = ExitKind::Crash;
}
} }
} }

View File

@ -1,7 +1,7 @@
use std::{path::PathBuf, sync::Mutex}; use std::{path::PathBuf, sync::Mutex};
use hashbrown::{hash_map::Entry, HashMap}; 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 libafl_targets::drcov::{DrCovBasicBlock, DrCovWriter};
use rangemap::RangeMap; use rangemap::RangeMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -83,7 +83,7 @@ where
fn pre_exec(&mut self, _emulator: &Emulator, _input: &S::Input) {} 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 self.full_trace {
if DRCOV_IDS.lock().unwrap().as_ref().unwrap().len() > self.drcov_len { if DRCOV_IDS.lock().unwrap().as_ref().unwrap().len() > self.drcov_len {
let mut drcov_vec = Vec::<DrCovBasicBlock>::new(); let mut drcov_vec = Vec::<DrCovBasicBlock>::new();

View File

@ -117,9 +117,11 @@ where
self.first_exec = false; self.first_exec = false;
} }
self.hooks.helpers_mut().pre_exec_all(&emu, input); self.hooks.helpers_mut().pre_exec_all(&emu, input);
let r = self.inner.run_target(fuzzer, state, mgr, input); let mut exit_kind = self.inner.run_target(fuzzer, state, mgr, input)?;
self.hooks.helpers_mut().post_exec_all(&emu, input); self.hooks
r .helpers_mut()
.post_exec_all(&emu, input, &mut exit_kind);
Ok(exit_kind)
} }
} }
@ -277,9 +279,11 @@ where
self.first_exec = false; self.first_exec = false;
} }
self.hooks.helpers_mut().pre_exec_all(&emu, input); self.hooks.helpers_mut().pre_exec_all(&emu, input);
let r = self.inner.run_target(fuzzer, state, mgr, input); let mut exit_kind = self.inner.run_target(fuzzer, state, mgr, input)?;
self.hooks.helpers_mut().post_exec_all(&emu, input); self.hooks
r .helpers_mut()
.post_exec_all(&emu, input, &mut exit_kind);
Ok(exit_kind)
} }
} }

View File

@ -1,6 +1,6 @@
use core::{fmt::Debug, ops::Range}; 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}; use crate::{emu::Emulator, hooks::QemuHooks};
@ -26,7 +26,7 @@ where
fn pre_exec(&mut self, _emulator: &Emulator, _input: &S::Input) {} 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<S>: MatchFirstType + Debug pub trait QemuHelperTuple<S>: MatchFirstType + Debug
@ -45,7 +45,7 @@ where
fn pre_exec_all(&mut self, _emulator: &Emulator, input: &S::Input); 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<S> QemuHelperTuple<S> for () impl<S> QemuHelperTuple<S> for ()
@ -68,7 +68,13 @@ where
fn pre_exec_all(&mut self, _emulator: &Emulator, _input: &S::Input) {} 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<Head, Tail, S> QemuHelperTuple<S> for (Head, Tail) impl<Head, Tail, S> QemuHelperTuple<S> for (Head, Tail)
@ -100,9 +106,9 @@ where
self.1.pre_exec_all(emulator, input); self.1.pre_exec_all(emulator, 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) {
self.0.post_exec(emulator, input); self.0.post_exec(emulator, input, exit_kind);
self.1.post_exec_all(emulator, input); self.1.post_exec_all(emulator, input, exit_kind);
} }
} }