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:
parent
53dba5f49d
commit
f8a4a020e8
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user