Define custom collectors for QemuCallTracerHelper (#1099)
* Define custom collectors for QemuCallTracerHelper and create OnCrashBacktraceCollector * fmt * clippy
This commit is contained in:
parent
3ffec79a17
commit
20c32316eb
@ -52,6 +52,8 @@ pub enum HarnessType {
|
||||
InProcess,
|
||||
/// Harness type when the target is a child process
|
||||
Child,
|
||||
/// Harness type with an external component filling the backtrace hash (e.g. `CrashBacktraceCollector` in `libafl_qemu`)
|
||||
External,
|
||||
}
|
||||
|
||||
/// An observer looking at the backtrace after the harness crashes
|
||||
@ -87,6 +89,17 @@ impl<'a> BacktraceObserver<'a> {
|
||||
fn clear_hash(&mut self) {
|
||||
*self.hash.as_mut() = None;
|
||||
}
|
||||
|
||||
/// Fill the hash value if the harness type is external
|
||||
pub fn fill_external(&mut self, hash: u64, exit_kind: &ExitKind) {
|
||||
if self.harness_type == HarnessType::External {
|
||||
if *exit_kind == ExitKind::Crash {
|
||||
self.update_hash(hash);
|
||||
} else {
|
||||
self.clear_hash();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ObserverWithHashField for BacktraceObserver<'a> {
|
||||
@ -108,7 +121,7 @@ where
|
||||
exit_kind: &ExitKind,
|
||||
) -> Result<(), Error> {
|
||||
if self.harness_type == HarnessType::InProcess {
|
||||
if exit_kind == &ExitKind::Crash {
|
||||
if *exit_kind == ExitKind::Crash {
|
||||
self.update_hash(collect_backtrace());
|
||||
} else {
|
||||
self.clear_hash();
|
||||
@ -124,7 +137,7 @@ where
|
||||
exit_kind: &ExitKind,
|
||||
) -> Result<(), Error> {
|
||||
if self.harness_type == HarnessType::Child {
|
||||
if exit_kind == &ExitKind::Crash {
|
||||
if *exit_kind == ExitKind::Crash {
|
||||
self.update_hash(collect_backtrace());
|
||||
} else {
|
||||
self.clear_hash();
|
||||
|
@ -6,7 +6,9 @@ use std::{
|
||||
sync::Mutex,
|
||||
};
|
||||
|
||||
use libafl::{executors::ExitKind, inputs::UsesInput, state::HasMetadata};
|
||||
use libafl::{
|
||||
executors::ExitKind, inputs::UsesInput, observers::ObserversTuple, state::HasMetadata,
|
||||
};
|
||||
use libc::{
|
||||
c_void, MAP_ANON, MAP_FAILED, MAP_FIXED, MAP_NORESERVE, MAP_PRIVATE, PROT_READ, PROT_WRITE,
|
||||
};
|
||||
@ -730,7 +732,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn post_exec(&mut self, emulator: &Emulator, _input: &S::Input, exit_kind: &mut ExitKind) {
|
||||
fn post_exec<OT>(
|
||||
&mut self,
|
||||
emulator: &Emulator,
|
||||
_input: &S::Input,
|
||||
_observers: &mut OT,
|
||||
exit_kind: &mut ExitKind,
|
||||
) where
|
||||
OT: ObserversTuple<S>,
|
||||
{
|
||||
if self.reset(emulator) == AsanRollback::HasLeaks {
|
||||
*exit_kind = ExitKind::Crash;
|
||||
}
|
||||
|
@ -1,27 +1,234 @@
|
||||
use core::fmt::Debug;
|
||||
|
||||
use capstone::prelude::*;
|
||||
use libafl::inputs::UsesInput;
|
||||
use libafl::{
|
||||
bolts::tuples::{MatchFirstType, Named},
|
||||
executors::ExitKind,
|
||||
inputs::{Input, UsesInput},
|
||||
observers::{stacktrace::BacktraceObserver, ObserversTuple},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
capstone,
|
||||
emu::Emulator,
|
||||
helper::{QemuHelper, QemuHelperTuple, QemuInstrumentationFilter},
|
||||
hooks::QemuHooks,
|
||||
Emulator, GuestAddr, Regs,
|
||||
GuestAddr, Regs,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct QemuCallTracerHelper {
|
||||
filter: QemuInstrumentationFilter,
|
||||
cs: Capstone,
|
||||
callstack: Vec<GuestAddr>,
|
||||
pub trait CallTraceCollector: 'static + Debug {
|
||||
fn on_call<QT, S>(
|
||||
&mut self,
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
call_len: usize,
|
||||
) where
|
||||
S: UsesInput,
|
||||
QT: QemuHelperTuple<S>;
|
||||
|
||||
fn on_ret<QT, S>(
|
||||
&mut self,
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
ret_addr: GuestAddr,
|
||||
) where
|
||||
S: UsesInput,
|
||||
QT: QemuHelperTuple<S>;
|
||||
|
||||
// Frowarded from the `QemuCallTracerHelper`
|
||||
fn pre_exec<I>(&mut self, _emulator: &Emulator, _input: &I)
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
}
|
||||
|
||||
fn post_exec<OT, S>(
|
||||
&mut self,
|
||||
_emulator: &Emulator,
|
||||
_input: &S::Input,
|
||||
_observers: &mut OT,
|
||||
_exit_kind: &mut ExitKind,
|
||||
) where
|
||||
OT: ObserversTuple<S>,
|
||||
S: UsesInput,
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
impl QemuCallTracerHelper {
|
||||
pub trait CallTraceCollectorTuple: 'static + MatchFirstType + Debug {
|
||||
fn on_call_all<QT, S>(
|
||||
&mut self,
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
call_len: usize,
|
||||
) where
|
||||
S: UsesInput,
|
||||
QT: QemuHelperTuple<S>;
|
||||
|
||||
fn on_ret_all<QT, S>(
|
||||
&mut self,
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_pc: GuestAddr,
|
||||
ret_addr: GuestAddr,
|
||||
) where
|
||||
S: UsesInput,
|
||||
QT: QemuHelperTuple<S>;
|
||||
|
||||
fn pre_exec_all<I>(&mut self, _emulator: &Emulator, input: &I)
|
||||
where
|
||||
I: Input;
|
||||
|
||||
fn post_exec_all<OT, S>(
|
||||
&mut self,
|
||||
_emulator: &Emulator,
|
||||
input: &S::Input,
|
||||
_observers: &mut OT,
|
||||
_exit_kind: &mut ExitKind,
|
||||
) where
|
||||
OT: ObserversTuple<S>,
|
||||
S: UsesInput;
|
||||
}
|
||||
|
||||
impl CallTraceCollectorTuple for () {
|
||||
fn on_call_all<QT, S>(
|
||||
&mut self,
|
||||
_hooks: &mut QemuHooks<'_, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_pc: GuestAddr,
|
||||
_call_len: usize,
|
||||
) where
|
||||
S: UsesInput,
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
}
|
||||
|
||||
fn on_ret_all<QT, S>(
|
||||
&mut self,
|
||||
_hooks: &mut QemuHooks<'_, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_pc: GuestAddr,
|
||||
_ret_addr: GuestAddr,
|
||||
) where
|
||||
S: UsesInput,
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
}
|
||||
|
||||
fn pre_exec_all<I>(&mut self, _emulator: &Emulator, _input: &I)
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
}
|
||||
|
||||
fn post_exec_all<OT, S>(
|
||||
&mut self,
|
||||
_emulator: &Emulator,
|
||||
_input: &S::Input,
|
||||
_observers: &mut OT,
|
||||
_exit_kind: &mut ExitKind,
|
||||
) where
|
||||
OT: ObserversTuple<S>,
|
||||
S: UsesInput,
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
impl<Head, Tail> CallTraceCollectorTuple for (Head, Tail)
|
||||
where
|
||||
Head: CallTraceCollector,
|
||||
Tail: CallTraceCollectorTuple,
|
||||
{
|
||||
fn on_call_all<QT, S>(
|
||||
&mut self,
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
mut state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
call_len: usize,
|
||||
) where
|
||||
S: UsesInput,
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
self.0.on_call(
|
||||
hooks,
|
||||
match state.as_mut() {
|
||||
Some(s) => Some(*s),
|
||||
None => None,
|
||||
},
|
||||
pc,
|
||||
call_len,
|
||||
);
|
||||
self.1.on_call_all(hooks, state, pc, call_len);
|
||||
}
|
||||
|
||||
fn on_ret_all<QT, S>(
|
||||
&mut self,
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
mut state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
ret_addr: GuestAddr,
|
||||
) where
|
||||
S: UsesInput,
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
self.0.on_ret(
|
||||
hooks,
|
||||
match state.as_mut() {
|
||||
Some(s) => Some(*s),
|
||||
None => None,
|
||||
},
|
||||
pc,
|
||||
ret_addr,
|
||||
);
|
||||
self.1.on_ret_all(hooks, state, pc, ret_addr);
|
||||
}
|
||||
|
||||
fn pre_exec_all<I>(&mut self, emulator: &Emulator, input: &I)
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
self.0.pre_exec(emulator, input);
|
||||
self.1.pre_exec_all(emulator, input);
|
||||
}
|
||||
|
||||
fn post_exec_all<OT, S>(
|
||||
&mut self,
|
||||
emulator: &Emulator,
|
||||
input: &S::Input,
|
||||
observers: &mut OT,
|
||||
exit_kind: &mut ExitKind,
|
||||
) where
|
||||
OT: ObserversTuple<S>,
|
||||
S: UsesInput,
|
||||
{
|
||||
self.0.post_exec(emulator, input, observers, exit_kind);
|
||||
self.1.post_exec_all(emulator, input, observers, exit_kind);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct QemuCallTracerHelper<T>
|
||||
where
|
||||
T: CallTraceCollectorTuple,
|
||||
{
|
||||
filter: QemuInstrumentationFilter,
|
||||
cs: Capstone,
|
||||
collectors: Option<T>,
|
||||
}
|
||||
|
||||
impl<T> QemuCallTracerHelper<T>
|
||||
where
|
||||
T: CallTraceCollectorTuple,
|
||||
{
|
||||
#[must_use]
|
||||
pub fn new(filter: QemuInstrumentationFilter) -> Self {
|
||||
pub fn new(filter: QemuInstrumentationFilter, collectors: T) -> Self {
|
||||
Self {
|
||||
filter,
|
||||
cs: capstone().detail(true).build().unwrap(),
|
||||
callstack: vec![],
|
||||
collectors: Some(collectors),
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,50 +237,11 @@ impl QemuCallTracerHelper {
|
||||
self.filter.allowed(addr)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn callstack(&self) -> &[GuestAddr] {
|
||||
&self.callstack
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.callstack.clear();
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for QemuCallTracerHelper {
|
||||
fn default() -> Self {
|
||||
Self::new(QemuInstrumentationFilter::None)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> QemuHelper<S> for QemuCallTracerHelper
|
||||
where
|
||||
S: UsesInput,
|
||||
{
|
||||
fn init_hooks<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
||||
fn on_ret<QT, S>(hooks: &mut QemuHooks<'_, QT, S>, state: Option<&mut S>, pc: GuestAddr)
|
||||
where
|
||||
S: UsesInput,
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
hooks.blocks(Some(gen_blocks_calls::<QT, S>), None);
|
||||
}
|
||||
|
||||
fn pre_exec(&mut self, _emulator: &Emulator, _input: &S::Input) {
|
||||
self.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/*pub fn on_call<QT, S>(hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, pc: GuestAddr)
|
||||
where
|
||||
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
}*/
|
||||
|
||||
pub fn on_ret<QT, S>(hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, _pc: GuestAddr)
|
||||
where
|
||||
S: UsesInput,
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
#[cfg(cpu_target = "x86_64")]
|
||||
let ret_addr = {
|
||||
let emu = hooks.emulator();
|
||||
@ -108,29 +276,33 @@ where
|
||||
|
||||
// log::info!("RET @ 0x{:#x}", ret_addr);
|
||||
|
||||
if let Some(h) = hooks
|
||||
let mut collectors = if let Some(h) = hooks.helpers_mut().match_first_type_mut::<Self>() {
|
||||
h.collectors.take()
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
collectors
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.on_ret_all(hooks, state, pc, ret_addr);
|
||||
hooks
|
||||
.helpers_mut()
|
||||
.match_first_type_mut::<QemuCallTracerHelper>()
|
||||
{
|
||||
while let Some(addr) = h.callstack.pop() {
|
||||
if addr == ret_addr {
|
||||
break;
|
||||
.match_first_type_mut::<Self>()
|
||||
.unwrap()
|
||||
.collectors = collectors;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gen_blocks_calls<QT, S>(
|
||||
fn gen_blocks_calls<QT, S>(
|
||||
hooks: &mut QemuHooks<'_, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
) -> Option<u64>
|
||||
where
|
||||
) -> Option<u64>
|
||||
where
|
||||
S: UsesInput,
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
{
|
||||
let emu = hooks.emulator();
|
||||
if let Some(h) = hooks.helpers().match_first_type::<QemuCallTracerHelper>() {
|
||||
if let Some(h) = hooks.helpers().match_first_type::<Self>() {
|
||||
if !h.must_instrument(pc) {
|
||||
return None;
|
||||
}
|
||||
@ -160,16 +332,28 @@ where
|
||||
for detail in insn_detail.groups() {
|
||||
match u32::from(detail.0) {
|
||||
capstone::InsnGroupType::CS_GRP_CALL => {
|
||||
// hooks.instruction_closure(insn.address() as GuestAddr, on_call, false);
|
||||
let call_len = insn.bytes().len() as GuestAddr;
|
||||
let call_cb = move |hooks: &mut QemuHooks<'_, QT, S>, _, pc| {
|
||||
let call_len = insn.bytes().len();
|
||||
// TODO do not use a closure, find a more efficient way to pass call_len
|
||||
let call_cb = move |hooks: &mut QemuHooks<'_, QT, S>,
|
||||
state: Option<&mut S>,
|
||||
pc| {
|
||||
// eprintln!("CALL @ 0x{:#x}", pc + call_len);
|
||||
if let Some(h) = hooks
|
||||
.helpers_mut()
|
||||
.match_first_type_mut::<QemuCallTracerHelper>()
|
||||
let mut collectors = if let Some(h) =
|
||||
hooks.helpers_mut().match_first_type_mut::<Self>()
|
||||
{
|
||||
h.callstack.push(pc + call_len);
|
||||
}
|
||||
h.collectors.take()
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
collectors
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.on_call_all(hooks, state, pc, call_len);
|
||||
hooks
|
||||
.helpers_mut()
|
||||
.match_first_type_mut::<Self>()
|
||||
.unwrap()
|
||||
.collectors = collectors;
|
||||
};
|
||||
unsafe {
|
||||
hooks.instruction_closure(
|
||||
@ -180,7 +364,7 @@ where
|
||||
}
|
||||
}
|
||||
capstone::InsnGroupType::CS_GRP_RET => {
|
||||
hooks.instruction(insn.address() as GuestAddr, on_ret, false);
|
||||
hooks.instruction(insn.address() as GuestAddr, Self::on_ret, false);
|
||||
break 'disasm;
|
||||
}
|
||||
capstone::InsnGroupType::CS_GRP_INVALID
|
||||
@ -207,4 +391,126 @@ where
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, T> QemuHelper<S> for QemuCallTracerHelper<T>
|
||||
where
|
||||
S: UsesInput,
|
||||
T: CallTraceCollectorTuple,
|
||||
{
|
||||
fn first_exec<QT>(&self, hooks: &QemuHooks<'_, QT, S>)
|
||||
where
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
hooks.blocks(Some(Self::gen_blocks_calls::<QT, S>), None);
|
||||
}
|
||||
|
||||
fn pre_exec(&mut self, emulator: &Emulator, input: &S::Input) {
|
||||
self.collectors
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.pre_exec_all(emulator, input);
|
||||
}
|
||||
|
||||
fn post_exec<OT>(
|
||||
&mut self,
|
||||
emulator: &Emulator,
|
||||
input: &S::Input,
|
||||
observers: &mut OT,
|
||||
exit_kind: &mut ExitKind,
|
||||
) where
|
||||
OT: ObserversTuple<S>,
|
||||
{
|
||||
self.collectors
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.post_exec_all(emulator, input, observers, exit_kind);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct OnCrashBacktraceCollector {
|
||||
callstack_hash: u64,
|
||||
observer_name: String,
|
||||
}
|
||||
|
||||
impl OnCrashBacktraceCollector {
|
||||
#[must_use]
|
||||
pub fn new(observer: &BacktraceObserver<'_>) -> Self {
|
||||
Self {
|
||||
callstack_hash: 0,
|
||||
observer_name: observer.name().to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_name(observer_name: String) -> Self {
|
||||
Self {
|
||||
callstack_hash: 0,
|
||||
observer_name,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn callstack_hash(&self) -> u64 {
|
||||
self.callstack_hash
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.callstack_hash = 0;
|
||||
}
|
||||
}
|
||||
|
||||
impl CallTraceCollector for OnCrashBacktraceCollector {
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
fn on_call<QT, S>(
|
||||
&mut self,
|
||||
_hooks: &mut QemuHooks<'_, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
pc: GuestAddr,
|
||||
call_len: usize,
|
||||
) where
|
||||
S: UsesInput,
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
self.callstack_hash ^= pc as u64 + call_len as u64;
|
||||
}
|
||||
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
fn on_ret<QT, S>(
|
||||
&mut self,
|
||||
_hooks: &mut QemuHooks<'_, QT, S>,
|
||||
_state: Option<&mut S>,
|
||||
_pc: GuestAddr,
|
||||
ret_addr: GuestAddr,
|
||||
) where
|
||||
S: UsesInput,
|
||||
QT: QemuHelperTuple<S>,
|
||||
{
|
||||
self.callstack_hash ^= ret_addr as u64;
|
||||
}
|
||||
|
||||
fn pre_exec<I>(&mut self, _emulator: &Emulator, _input: &I)
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
self.reset();
|
||||
}
|
||||
|
||||
fn post_exec<OT, S>(
|
||||
&mut self,
|
||||
_emulator: &Emulator,
|
||||
_input: &S::Input,
|
||||
observers: &mut OT,
|
||||
exit_kind: &mut ExitKind,
|
||||
) where
|
||||
OT: ObserversTuple<S>,
|
||||
S: UsesInput,
|
||||
{
|
||||
let observer = observers
|
||||
.match_name_mut::<BacktraceObserver<'_>>(&self.observer_name)
|
||||
.expect("A OnCrashBacktraceCollector needs a BacktraceObserver");
|
||||
observer.fill_external(self.callstack_hash, exit_kind);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
use std::{path::PathBuf, sync::Mutex};
|
||||
|
||||
use hashbrown::{hash_map::Entry, HashMap};
|
||||
use libafl::{executors::ExitKind, inputs::UsesInput, state::HasMetadata};
|
||||
use libafl::{
|
||||
executors::ExitKind, inputs::UsesInput, observers::ObserversTuple, state::HasMetadata,
|
||||
};
|
||||
use libafl_targets::drcov::{DrCovBasicBlock, DrCovWriter};
|
||||
use rangemap::RangeMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -84,7 +86,15 @@ where
|
||||
|
||||
fn pre_exec(&mut self, _emulator: &Emulator, _input: &S::Input) {}
|
||||
|
||||
fn post_exec(&mut self, emulator: &Emulator, _input: &S::Input, _exit_kind: &mut ExitKind) {
|
||||
fn post_exec<OT>(
|
||||
&mut self,
|
||||
emulator: &Emulator,
|
||||
_input: &S::Input,
|
||||
_observers: &mut OT,
|
||||
_exit_kind: &mut ExitKind,
|
||||
) where
|
||||
OT: ObserversTuple<S>,
|
||||
{
|
||||
if self.full_trace {
|
||||
if DRCOV_IDS.lock().unwrap().as_ref().unwrap().len() > self.drcov_len {
|
||||
let mut drcov_vec = Vec::<DrCovBasicBlock>::new();
|
||||
|
@ -463,7 +463,7 @@ impl Drop for GuestMaps {
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub(crate) struct FatPtr(pub *const c_void, pub *const c_void);
|
||||
|
||||
static mut GDB_COMMANDS: Vec<FatPtr> = vec![];
|
||||
|
@ -126,9 +126,12 @@ where
|
||||
}
|
||||
self.hooks.helpers_mut().pre_exec_all(&emu, input);
|
||||
let mut exit_kind = self.inner.run_target(fuzzer, state, mgr, input)?;
|
||||
self.hooks
|
||||
.helpers_mut()
|
||||
.post_exec_all(&emu, input, &mut exit_kind);
|
||||
self.hooks.helpers_mut().post_exec_all(
|
||||
&emu,
|
||||
input,
|
||||
self.inner.observers_mut(),
|
||||
&mut exit_kind,
|
||||
);
|
||||
Ok(exit_kind)
|
||||
}
|
||||
}
|
||||
@ -288,9 +291,12 @@ where
|
||||
}
|
||||
self.hooks.helpers_mut().pre_exec_all(&emu, input);
|
||||
let mut exit_kind = self.inner.run_target(fuzzer, state, mgr, input)?;
|
||||
self.hooks
|
||||
.helpers_mut()
|
||||
.post_exec_all(&emu, input, &mut exit_kind);
|
||||
self.hooks.helpers_mut().post_exec_all(
|
||||
&emu,
|
||||
input,
|
||||
self.inner.observers_mut(),
|
||||
&mut exit_kind,
|
||||
);
|
||||
Ok(exit_kind)
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
use core::{fmt::Debug, ops::Range};
|
||||
|
||||
use libafl::{bolts::tuples::MatchFirstType, executors::ExitKind, inputs::UsesInput};
|
||||
use libafl::{
|
||||
bolts::tuples::MatchFirstType, executors::ExitKind, inputs::UsesInput,
|
||||
observers::ObserversTuple,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
emu::{Emulator, GuestAddr},
|
||||
@ -29,7 +32,16 @@ where
|
||||
|
||||
fn pre_exec(&mut self, _emulator: &Emulator, _input: &S::Input) {}
|
||||
|
||||
fn post_exec(&mut self, _emulator: &Emulator, _input: &S::Input, _exit_kind: &mut ExitKind) {}
|
||||
fn post_exec<OT>(
|
||||
&mut self,
|
||||
_emulator: &Emulator,
|
||||
_input: &S::Input,
|
||||
_observers: &mut OT,
|
||||
_exit_kind: &mut ExitKind,
|
||||
) where
|
||||
OT: ObserversTuple<S>,
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
pub trait QemuHelperTuple<S>: MatchFirstType + Debug
|
||||
@ -48,7 +60,14 @@ where
|
||||
|
||||
fn pre_exec_all(&mut self, _emulator: &Emulator, input: &S::Input);
|
||||
|
||||
fn post_exec_all(&mut self, _emulator: &Emulator, input: &S::Input, _exit_kind: &mut ExitKind);
|
||||
fn post_exec_all<OT>(
|
||||
&mut self,
|
||||
_emulator: &Emulator,
|
||||
input: &S::Input,
|
||||
_observers: &mut OT,
|
||||
_exit_kind: &mut ExitKind,
|
||||
) where
|
||||
OT: ObserversTuple<S>;
|
||||
}
|
||||
|
||||
impl<S> QemuHelperTuple<S> for ()
|
||||
@ -71,12 +90,15 @@ where
|
||||
|
||||
fn pre_exec_all(&mut self, _emulator: &Emulator, _input: &S::Input) {}
|
||||
|
||||
fn post_exec_all(
|
||||
fn post_exec_all<OT>(
|
||||
&mut self,
|
||||
_emulator: &Emulator,
|
||||
_input: &S::Input,
|
||||
_observers: &mut OT,
|
||||
_exit_kind: &mut ExitKind,
|
||||
) {
|
||||
) where
|
||||
OT: ObserversTuple<S>,
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,9 +131,17 @@ where
|
||||
self.1.pre_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);
|
||||
fn post_exec_all<OT>(
|
||||
&mut self,
|
||||
emulator: &Emulator,
|
||||
input: &S::Input,
|
||||
observers: &mut OT,
|
||||
exit_kind: &mut ExitKind,
|
||||
) where
|
||||
OT: ObserversTuple<S>,
|
||||
{
|
||||
self.0.post_exec(emulator, input, observers, exit_kind);
|
||||
self.1.post_exec_all(emulator, input, observers, exit_kind);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,8 +19,8 @@ use crate::{
|
||||
};
|
||||
|
||||
// all kinds of hooks
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
enum Hook {
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub(crate) enum Hook {
|
||||
Function(*const c_void),
|
||||
Closure(FatPtr),
|
||||
#[cfg(emulation_mode = "usermode")]
|
||||
|
Loading…
x
Reference in New Issue
Block a user