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,
};
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;
}
}
}

View File

@ -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::<DrCovBasicBlock>::new();

View File

@ -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)
}
}

View File

@ -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<S>: 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<S> QemuHelperTuple<S> 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<Head, Tail, S> QemuHelperTuple<S> 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);
}
}