Unify qemu executor (#2483)

* Remove stateless qemu executor

* All harnesses take a reference to an emulator as parameter now

* harness takes an emulator as first parameter, and input as second parameter (opposite of previous definition)

* bump libafl qemu dependencies to the latest version
This commit is contained in:
Romain Malmain 2024-08-13 19:44:10 +02:00 committed by GitHub
parent 00806b177d
commit 13ba32ed2a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 153 additions and 450 deletions

View File

@ -156,7 +156,7 @@ fn fuzz(
CmpLogChildModule::default(),
);
let mut emulator = Emulator::new(
let emulator = Emulator::new(
args.as_slice(),
env.as_slice(),
emulator_modules,
@ -356,7 +356,7 @@ fn fuzz(
};
let executor = QemuForkExecutor::new(
&mut emulator,
emulator,
&mut harness,
tuple_list!(edges_observer, time_observer),
&mut fuzzer,

View File

@ -329,7 +329,7 @@ fn fuzz(
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
// The wrapped harness function, calling out to the LLVM-style harness
let mut harness = |input: &BytesInput| {
let mut harness = |_emulator: &mut Emulator<_, _, _, _>, input: &BytesInput| {
let target = input.target_bytes();
let mut buf = target.as_slice();
let mut len = buf.len();
@ -366,12 +366,12 @@ fn fuzz(
//QemuSnapshotHelper::new()
);
let mut emulator =
let emulator =
Emulator::new_with_qemu(qemu, modules, NopEmulatorExitHandler, NopCommandManager)?;
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
let executor = QemuExecutor::new(
&mut emulator,
emulator,
&mut harness,
tuple_list!(edges_observer, time_observer),
&mut fuzzer,

View File

@ -223,11 +223,11 @@ pub fn fuzz() -> Result<(), Error> {
let modules = tuple_list!(EdgeCoverageChildModule::default(),);
let mut emulator =
let emulator =
Emulator::new_with_qemu(qemu, modules, NopEmulatorExitHandler, NopCommandManager)?;
let mut executor = QemuForkExecutor::new(
&mut emulator,
emulator,
&mut harness,
tuple_list!(edges_observer),
&mut fuzzer,

View File

@ -178,7 +178,7 @@ pub fn fuzz() {
}
};
let mut harness = |input: &BytesInput| {
let mut harness = |_emulator: &mut Emulator<_, _, _, _>, input: &BytesInput| {
let target = input.target_bytes();
let mut buf = target.as_slice();
let mut len = buf.len();
@ -241,7 +241,7 @@ pub fn fuzz() {
false,
));
let mut emulator = Emulator::new_with_qemu(
let emulator = Emulator::new_with_qemu(
qemu,
emulator_modules,
NopEmulatorExitHandler,
@ -250,7 +250,7 @@ pub fn fuzz() {
.unwrap();
let mut executor = QemuExecutor::new(
&mut emulator,
emulator,
&mut harness,
(),
&mut fuzzer,

View File

@ -149,12 +149,13 @@ impl<'a, M: Monitor> Instance<'a, M> {
state.add_metadata(tokens);
let harness = Harness::new(self.qemu)?;
let mut harness = |input: &BytesInput| harness.run(input);
let mut harness =
|_emulator: &mut Emulator<_, _, _, _>, input: &BytesInput| harness.run(input);
// A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
let mut emulator = Emulator::new_with_qemu(
let emulator = Emulator::new_with_qemu(
*self.qemu,
modules,
NopEmulatorExitHandler,
@ -165,7 +166,7 @@ impl<'a, M: Monitor> Instance<'a, M> {
if self.options.is_cmplog_core(self.core_id) {
// Create a QEMU in-process executor
let executor = QemuExecutor::new(
&mut emulator,
emulator,
&mut harness,
observers,
&mut fuzzer,
@ -203,7 +204,7 @@ impl<'a, M: Monitor> Instance<'a, M> {
} else {
// Create a QEMU in-process executor
let mut executor = QemuExecutor::new(
&mut emulator,
emulator,
&mut harness,
observers,
&mut fuzzer,

View File

@ -25,9 +25,9 @@ lto = "fat"
codegen-units = 1
[dependencies]
libafl = { path = "../../../libafl/" }
libafl_bolts = { path = "../../../libafl_bolts/" }
libafl_qemu = { path = "../../../libafl_qemu/", features = [
libafl = { path = "../../../libafl" }
libafl_bolts = { path = "../../../libafl_bolts" }
libafl_qemu = { path = "../../../libafl_qemu", features = [
"arm",
"systemmode",
] }

View File

@ -32,7 +32,7 @@ use libafl_qemu::{
command::{EndCommand, StartCommand, StdCommandManager},
elf::EasyElf,
emu::Emulator,
executor::{stateful::StatefulQemuExecutor, QemuExecutorState},
executor::QemuExecutor,
modules::edges::{
edges_map_mut_ptr, EdgeCoverageModule, EDGES_MAP_SIZE_IN_USE, MAX_EDGES_FOUND,
},
@ -103,7 +103,7 @@ pub fn fuzz() {
let modules = tuple_list!(EdgeCoverageModule::default());
// Create emulator
let mut emu = Emulator::new(&args, &env, modules, emu_exit_handler, cmd_manager).unwrap();
let emu = Emulator::new(&args, &env, modules, emu_exit_handler, cmd_manager).unwrap();
// Set breakpoints of interest with corresponding commands.
emu.add_breakpoint(
@ -127,14 +127,8 @@ pub fn fuzz() {
println!("Devices = {:?}", devices);
// The wrapped harness function, calling out to the LLVM-style harness
let mut harness =
|input: &BytesInput, qemu_executor_state: &mut QemuExecutorState<_, _, _, _>| unsafe {
qemu_executor_state
.emulator_mut()
.run(input)
.unwrap()
.try_into()
.unwrap()
let mut harness = |emulator: &mut Emulator<_, _, _, _>, input: &BytesInput| unsafe {
emulator.run(input).unwrap().try_into().unwrap()
};
// Create an observation channel using the coverage map
@ -197,8 +191,8 @@ pub fn fuzz() {
);
// Create a QEMU in-process executor
let mut executor = StatefulQemuExecutor::new(
&mut emu,
let mut executor = QemuExecutor::new(
emu,
&mut harness,
tuple_list!(edges_observer, time_observer),
&mut fuzzer,

View File

@ -32,7 +32,7 @@ use libafl_bolts::{
use libafl_qemu::{
command::NopCommandManager,
elf::EasyElf,
executor::{stateful::StatefulQemuExecutor, QemuExecutorState},
executor::QemuExecutor,
modules::edges::{
edges_map_mut_ptr, EdgeCoverageModule, EDGES_MAP_SIZE_IN_USE, MAX_EDGES_FOUND,
},
@ -93,7 +93,7 @@ pub fn fuzz() {
let emulator_modules = tuple_list!(EdgeCoverageModule::default());
let mut emulator = Emulator::new(
let emulator = Emulator::new(
args.as_slice(),
env.as_slice(),
emulator_modules,
@ -129,8 +129,7 @@ pub fn fuzz() {
let snap = qemu.create_fast_snapshot(true);
// The wrapped harness function, calling out to the LLVM-style harness
let mut harness = |input: &BytesInput, state: &mut QemuExecutorState<_, _, _, _>| {
let emulator = state.emulator_mut();
let mut harness = |emulator: &mut Emulator<_, _, _, _>, input: &BytesInput| {
let target = input.target_bytes();
let mut buf = target.as_slice();
let len = buf.len();
@ -229,8 +228,8 @@ pub fn fuzz() {
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
// Create a QEMU in-process executor
let mut executor = StatefulQemuExecutor::new(
&mut emulator,
let mut executor = QemuExecutor::new(
emulator,
&mut harness,
tuple_list!(edges_observer, time_observer),
&mut fuzzer,

View File

@ -29,7 +29,7 @@ use libafl_bolts::{
use libafl_qemu::{
command::StdCommandManager,
emu::Emulator,
executor::{stateful::StatefulQemuExecutor, QemuExecutorState},
executor::QemuExecutor,
modules::edges::{
edges_map_mut_ptr, EdgeCoverageModule, EDGES_MAP_SIZE_IN_USE, MAX_EDGES_FOUND,
},
@ -66,20 +66,14 @@ pub fn fuzz() {
// Choose modules to use
let modules = tuple_list!(EdgeCoverageModule::default());
let mut emu = Emulator::new(&args, &env, modules, emu_exit_handler, cmd_manager).unwrap(); // Create the emulator
let emu = Emulator::new(&args, &env, modules, emu_exit_handler, cmd_manager).unwrap(); // Create the emulator
let devices = emu.list_devices();
println!("Devices = {:?}", devices);
// The wrapped harness function, calling out to the LLVM-style harness
let mut harness =
|input: &BytesInput, qemu_executor_state: &mut QemuExecutorState<_, _, _, _>| unsafe {
qemu_executor_state
.emulator_mut()
.run(input)
.unwrap()
.try_into()
.unwrap()
let mut harness = |emulator: &mut Emulator<_, _, _, _>, input: &BytesInput| unsafe {
emulator.run(input).unwrap().try_into().unwrap()
};
// Create an observation channel using the coverage map
@ -142,8 +136,8 @@ pub fn fuzz() {
);
// Create a QEMU in-process executor
let mut executor = StatefulQemuExecutor::new(
&mut emu,
let mut executor = QemuExecutor::new(
emu,
&mut harness,
tuple_list!(edges_observer, time_observer),
&mut fuzzer,

View File

@ -33,8 +33,8 @@ pub type StatefulInProcessExecutor<'a, H, OT, S, ES> =
/// The process executor simply calls a target function, as boxed `FnMut` trait object
/// The internal state of the executor is made available to the harness.
pub type OwnedInProcessExecutor<OT, S, ES> = StatefulGenericInProcessExecutor<
dyn FnMut(&<S as UsesInput>::Input, &mut ES) -> ExitKind,
Box<dyn FnMut(&<S as UsesInput>::Input, &mut ES) -> ExitKind>,
dyn FnMut(&mut ES, &<S as UsesInput>::Input) -> ExitKind,
Box<dyn FnMut(&mut ES, &<S as UsesInput>::Input) -> ExitKind>,
(),
OT,
S,
@ -46,7 +46,7 @@ pub type OwnedInProcessExecutor<OT, S, ES> = StatefulGenericInProcessExecutor<
#[allow(dead_code)]
pub struct StatefulGenericInProcessExecutor<H, HB, HT, OT, S, ES>
where
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized,
H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
HB: BorrowMut<H>,
HT: ExecutorHooksTuple<S>,
OT: ObserversTuple<S>,
@ -63,7 +63,7 @@ where
impl<H, HB, HT, OT, S, ES> Debug for StatefulGenericInProcessExecutor<H, HB, HT, OT, S, ES>
where
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized,
H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
HB: BorrowMut<H>,
HT: ExecutorHooksTuple<S>,
OT: ObserversTuple<S> + Debug,
@ -79,7 +79,7 @@ where
impl<H, HB, HT, OT, S, ES> UsesState for StatefulGenericInProcessExecutor<H, HB, HT, OT, S, ES>
where
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized,
H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
HB: BorrowMut<H>,
HT: ExecutorHooksTuple<S>,
OT: ObserversTuple<S>,
@ -90,7 +90,7 @@ where
impl<H, HB, HT, OT, S, ES> UsesObservers for StatefulGenericInProcessExecutor<H, HB, HT, OT, S, ES>
where
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized,
H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
HB: BorrowMut<H>,
HT: ExecutorHooksTuple<S>,
OT: ObserversTuple<S>,
@ -103,7 +103,7 @@ impl<EM, H, HB, HT, OT, S, Z, ES> Executor<EM, Z>
for StatefulGenericInProcessExecutor<H, HB, HT, OT, S, ES>
where
EM: UsesState<State = S>,
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized,
H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
HB: BorrowMut<H>,
HT: ExecutorHooksTuple<S>,
OT: ObserversTuple<S>,
@ -125,7 +125,7 @@ where
}
self.inner.hooks.pre_exec_all(state, input);
let ret = self.harness_fn.borrow_mut()(input, &mut self.exposed_executor_state);
let ret = self.harness_fn.borrow_mut()(&mut self.exposed_executor_state, input);
self.inner.hooks.post_exec_all(state, input);
self.inner.leave_target(fuzzer, state, mgr, input);
@ -135,7 +135,7 @@ where
impl<H, HB, HT, OT, S, ES> HasObservers for StatefulGenericInProcessExecutor<H, HB, HT, OT, S, ES>
where
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized,
H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
HB: BorrowMut<H>,
HT: ExecutorHooksTuple<S>,
OT: ObserversTuple<S>,
@ -154,7 +154,7 @@ where
impl<'a, H, OT, S, ES> StatefulInProcessExecutor<'a, H, OT, S, ES>
where
H: FnMut(&<S as UsesInput>::Input, &mut ES) -> ExitKind + ?Sized,
H: FnMut(&mut ES, &<S as UsesInput>::Input) -> ExitKind + ?Sized,
OT: ObserversTuple<S>,
S: HasExecutions + HasSolutions + HasCorpus + State,
{
@ -265,7 +265,7 @@ where
impl<H, HB, HT, OT, S, ES> StatefulGenericInProcessExecutor<H, HB, HT, OT, S, ES>
where
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized,
H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
HB: BorrowMut<H>,
HT: ExecutorHooksTuple<S>,
OT: ObserversTuple<S>,
@ -284,7 +284,7 @@ where
impl<H, HB, HT, OT, S, ES> StatefulGenericInProcessExecutor<H, HB, HT, OT, S, ES>
where
H: FnMut(&S::Input, &mut ES) -> ExitKind + ?Sized,
H: FnMut(&mut ES, &S::Input) -> ExitKind + ?Sized,
HB: BorrowMut<H>,
HT: ExecutorHooksTuple<S>,
OT: ObserversTuple<S>,
@ -414,7 +414,7 @@ where
impl<H, HB, HT, OT, S, ES> HasInProcessHooks<S>
for StatefulGenericInProcessExecutor<H, HB, HT, OT, S, ES>
where
H: FnMut(&<S as UsesInput>::Input, &mut ES) -> ExitKind + ?Sized,
H: FnMut(&mut ES, &<S as UsesInput>::Input) -> ExitKind + ?Sized,
HB: BorrowMut<H>,
HT: ExecutorHooksTuple<S>,
OT: ObserversTuple<S>,

View File

@ -110,14 +110,14 @@ goblin = "0.8"
libc = "0.2"
strum = "0.26"
strum_macros = "0.26"
syscall-numbers = "3.0"
syscall-numbers = "4.0"
meminterval = "0.4"
thread_local = "1.1.4"
capstone = "0.12.0"
rangemap = "1.3"
log = "0.4"
object = "0.36"
addr2line = "0.23"
addr2line = "0.24"
typed-arena = "2.0"
paste = "1"
enum-map = "2.7"

View File

@ -58,6 +58,7 @@ const WRAPPER_HEADER: &str = r#"
#include "hw/core/sysemu-cpu-ops.h"
#include "exec/address-spaces.h"
#include "sysemu/tcg.h"
#include "sysemu/runstate.h"
#include "sysemu/replay.h"
#include "libafl/syx-snapshot/device-save.h"
@ -148,6 +149,7 @@ pub fn generate(
.allowlist_type("libafl_mapinfo")
.allowlist_type("IntervalTreeRoot")
.allowlist_function("qemu_user_init")
.allowlist_function("qemu_system_debug_request")
.allowlist_function("target_mmap")
.allowlist_function("target_mprotect")
.allowlist_function("target_munmap")

View File

@ -1,11 +1,11 @@
//! A `QEMU`-based executor for binary-only instrumentation in `LibAFL`
#[cfg(emulation_mode = "usermode")]
use core::ptr;
use core::{
ffi::c_void,
fmt::{self, Debug, Formatter},
time::Duration,
};
#[cfg(emulation_mode = "usermode")]
use std::ptr;
#[cfg(feature = "fork")]
use libafl::{
@ -15,7 +15,7 @@ use libafl::{
events::{EventFirer, EventRestarter},
executors::{
hooks::inprocess::InProcessExecutorHandlerData,
inprocess::{HasInProcessHooks, InProcessExecutor},
inprocess::{stateful::StatefulInProcessExecutor, HasInProcessHooks},
Executor, ExitKind, HasObservers,
},
feedbacks::Feedback,
@ -30,58 +30,29 @@ use libafl_bolts::{
os::unix_signals::{siginfo_t, ucontext_t, Signal},
tuples::RefIndexable,
};
#[cfg(emulation_mode = "systemmode")]
use libafl_qemu_sys::qemu_system_debug_request;
#[cfg(emulation_mode = "usermode")]
use crate::emu::EmulatorModules;
use crate::EmulatorModules;
use crate::{command::CommandManager, modules::EmulatorModuleTuple, Emulator, EmulatorExitHandler};
/// A version of `QemuExecutor` with a state accessible from the harness.
pub mod stateful;
pub struct QemuExecutorState<'a, CM, EH, ET, S>
where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{
emulator: &'a mut Emulator<CM, EH, ET, S>,
#[cfg(emulation_mode = "usermode")]
extern "C" {
// Original QEMU user signal handler
fn libafl_qemu_handle_crash(signal: i32, info: *mut siginfo_t, puc: *mut c_void);
}
pub struct QemuExecutor<'a, CM, EH, H, OT, ET, S>
where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&S::Input) -> ExitKind,
H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind,
S: Unpin + State + HasExecutions,
OT: ObserversTuple<S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{
inner: InProcessExecutor<'a, H, OT, S>,
state: QemuExecutorState<'a, CM, EH, ET, S>,
}
impl<'a, CM, EH, H, OT, ET, S> Debug for QemuExecutor<'a, CM, EH, H, OT, ET, S>
where
CM: CommandManager<EH, ET, S> + Debug,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&S::Input) -> ExitKind,
S: Unpin + State + HasExecutions + Debug,
OT: ObserversTuple<S> + Debug,
ET: EmulatorModuleTuple<S> + Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("QemuExecutor")
.field("emulator", &self.state.emulator)
.field("inner", &self.inner)
.finish()
}
}
#[cfg(emulation_mode = "usermode")]
extern "C" {
// Original QEMU user signal handler
fn libafl_qemu_handle_crash(signal: i32, info: *mut siginfo_t, puc: *mut c_void);
inner: StatefulInProcessExecutor<'a, H, OT, S, Emulator<CM, EH, ET, S>>,
}
#[cfg(emulation_mode = "usermode")]
@ -103,17 +74,12 @@ pub unsafe fn inproc_qemu_crash_handler<'a, E, EM, OF, Z, ET, S>(
Some(v) => ptr::from_mut::<ucontext_t>(*v) as *mut c_void,
None => ptr::null_mut(),
};
libafl_qemu_handle_crash(signal as i32, info, puc);
libafl_qemu_handle_crash(signal as i32, std::ptr::from_mut::<siginfo_t>(info), puc);
}
#[cfg(emulation_mode = "systemmode")]
pub(crate) static mut BREAK_ON_TMOUT: bool = false;
#[cfg(emulation_mode = "systemmode")]
extern "C" {
fn qemu_system_debug_request();
}
#[cfg(emulation_mode = "systemmode")]
pub unsafe fn inproc_qemu_timeout_handler<'a, E, EM, OF, Z>(
signal: Signal,
@ -136,58 +102,19 @@ pub unsafe fn inproc_qemu_timeout_handler<'a, E, EM, OF, Z>(
}
}
impl<'a, CM, EH, ET, S> QemuExecutorState<'a, CM, EH, ET, S>
impl<'a, CM, EH, H, OT, ET, S> Debug for QemuExecutor<'a, CM, EH, H, OT, ET, S>
where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind,
S: Unpin + State + HasExecutions,
OT: ObserversTuple<S> + Debug,
ET: EmulatorModuleTuple<S> + Debug,
S: Unpin + State + HasExecutions + HasCorpus + HasSolutions,
{
#[cfg(emulation_mode = "systemmode")]
pub fn new<E, EM, OF, OT, Z>(emulator: &'a mut Emulator<CM, EH, ET, S>) -> Result<Self, Error>
where
E: Executor<EM, Z, State = S> + HasInProcessHooks<S> + HasObservers,
EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<S>,
OT: ObserversTuple<S>,
Z: HasObjective<Objective = OF, State = S>,
{
Ok(QemuExecutorState { emulator })
}
#[cfg(emulation_mode = "usermode")]
pub fn new<E, EM, OF, OT, Z>(emulator: &'a mut Emulator<CM, EH, ET, S>) -> Result<Self, Error>
where
E: Executor<EM, Z, State = S> + HasInProcessHooks<S> + HasObservers,
EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<S>,
OT: ObserversTuple<S>,
Z: HasObjective<Objective = OF, State = S> + ExecutionProcessor + HasScheduler,
{
#[cfg(emulation_mode = "usermode")]
{
let handler = |emulator_modules: &mut EmulatorModules<ET, S>, host_sig| {
eprintln!("Crashed with signal {host_sig}");
unsafe {
libafl::executors::inprocess::generic_inproc_crash_handler::<E, EM, OF, Z>();
}
if let Some(cpu) = emulator_modules.qemu().current_cpu() {
eprint!("Context:\n{}", cpu.display_context());
}
};
emulator.modules_mut().crash_closure(Box::new(handler));
}
Ok(QemuExecutorState { emulator })
}
#[must_use]
pub fn emulator(&self) -> &Emulator<CM, EH, ET, S> {
self.emulator
}
pub fn emulator_mut(&mut self) -> &mut Emulator<CM, EH, ET, S> {
self.emulator
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("QemuExecutor")
.field("inner", &self.inner)
.finish()
}
}
@ -195,13 +122,13 @@ impl<'a, CM, EH, H, OT, ET, S> QemuExecutor<'a, CM, EH, H, OT, ET, S>
where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&S::Input) -> ExitKind,
H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind,
S: Unpin + State + HasExecutions,
OT: ObserversTuple<S>,
ET: EmulatorModuleTuple<S> + Debug,
{
pub fn new<EM, OF, Z>(
emulator: &'a mut Emulator<CM, EH, ET, S>,
emulator: Emulator<CM, EH, ET, S>,
harness_fn: &'a mut H,
observers: OT,
fuzzer: &mut Z,
@ -215,31 +142,51 @@ where
S: Unpin + State + HasExecutions + HasCorpus + HasSolutions,
Z: HasObjective<Objective = OF, State = S> + HasScheduler + ExecutionProcessor,
{
let mut inner = InProcessExecutor::with_timeout(
harness_fn, observers, fuzzer, state, event_mgr, timeout,
let mut inner = StatefulInProcessExecutor::with_timeout(
harness_fn, emulator, observers, fuzzer, state, event_mgr, timeout,
)?;
#[cfg(emulation_mode = "usermode")]
{
inner.inprocess_hooks_mut().crash_handler =
inproc_qemu_crash_handler::<InProcessExecutor<'a, H, OT, S>, EM, OF, Z, ET, S>
as *const c_void;
inner.inprocess_hooks_mut().crash_handler = inproc_qemu_crash_handler::<
StatefulInProcessExecutor<'a, H, OT, S, Emulator<CM, EH, ET, S>>,
EM,
OF,
Z,
ET,
S,
> as *const c_void;
let handler = |emulator_modules: &mut EmulatorModules<ET, S>, host_sig| {
eprintln!("Crashed with signal {host_sig}");
unsafe {
libafl::executors::inprocess::generic_inproc_crash_handler::<Self, EM, OF, Z>();
}
if let Some(cpu) = emulator_modules.qemu().current_cpu() {
eprint!("Context:\n{}", cpu.display_context());
}
};
inner
.exposed_executor_state_mut()
.modules_mut()
.crash_closure(Box::new(handler));
}
#[cfg(emulation_mode = "systemmode")]
{
inner.inprocess_hooks_mut().timeout_handler =
inproc_qemu_timeout_handler::<InProcessExecutor<'a, H, OT, S>, EM, OF, Z>
as *const c_void;
inner.inprocess_hooks_mut().timeout_handler = inproc_qemu_timeout_handler::<
StatefulInProcessExecutor<'a, H, OT, S, Emulator<CM, EH, ET, S>>,
EM,
OF,
Z,
> as *const c_void;
}
let state =
QemuExecutorState::new::<InProcessExecutor<'a, H, OT, S>, EM, OF, OT, Z>(emulator)?;
Ok(Self { inner, state })
Ok(Self { inner })
}
pub fn inner(&self) -> &InProcessExecutor<'a, H, OT, S> {
pub fn inner(&self) -> &StatefulInProcessExecutor<'a, H, OT, S, Emulator<CM, EH, ET, S>> {
&self.inner
}
@ -250,43 +197,10 @@ where
}
}
pub fn inner_mut(&mut self) -> &mut InProcessExecutor<'a, H, OT, S> {
&mut self.inner
}
}
impl<'a, CM, EH, ET, S> QemuExecutorState<'a, CM, EH, ET, S>
where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{
fn pre_exec<E, EM, OF, Z>(&mut self, input: &E::Input)
where
E: Executor<EM, Z, State = S>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<S>,
Z: HasObjective<Objective = OF, State = S>,
{
self.emulator.first_exec_all();
self.emulator.pre_exec_all(input);
}
fn post_exec<E, EM, OT, OF, Z>(
pub fn inner_mut(
&mut self,
input: &E::Input,
observers: &mut OT,
exit_kind: &mut ExitKind,
) where
E: Executor<EM, Z, State = S> + HasObservers,
EM: EventFirer<State = S> + EventRestarter<State = S>,
OT: ObserversTuple<S>,
OF: Feedback<S>,
Z: HasObjective<Objective = OF, State = S>,
{
self.emulator.post_exec_all(input, observers, exit_kind);
) -> &mut StatefulInProcessExecutor<'a, H, OT, S, Emulator<CM, EH, ET, S>> {
&mut self.inner
}
}
@ -295,7 +209,7 @@ where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
H: FnMut(&S::Input) -> ExitKind,
H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind,
S: Unpin + State + HasExecutions + HasCorpus + HasSolutions,
OT: ObserversTuple<S>,
OF: Feedback<S>,
@ -309,13 +223,18 @@ where
mgr: &mut EM,
input: &Self::Input,
) -> Result<ExitKind, Error> {
self.state.pre_exec::<Self, EM, OF, Z>(input);
self.inner.exposed_executor_state_mut().first_exec_all();
self.inner.exposed_executor_state_mut().pre_exec_all(input);
let mut exit_kind = self.inner.run_target(fuzzer, state, mgr, input)?;
self.state.post_exec::<Self, EM, OT, OF, Z>(
self.inner.exposed_executor_state.post_exec_all(
input,
&mut *self.inner.observers_mut(),
&mut *self.inner.inner.observers_mut(),
&mut exit_kind,
);
Ok(exit_kind)
}
}
@ -324,7 +243,7 @@ impl<'a, CM, EH, H, OT, ET, S> UsesState for QemuExecutor<'a, CM, EH, H, OT, ET,
where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&S::Input) -> ExitKind,
H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind,
OT: ObserversTuple<S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
@ -336,7 +255,7 @@ impl<'a, CM, EH, H, OT, ET, S> UsesObservers for QemuExecutor<'a, CM, EH, H, OT,
where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&S::Input) -> ExitKind,
H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind,
OT: ObserversTuple<S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
@ -348,7 +267,7 @@ impl<'a, CM, EH, H, OT, ET, S> HasObservers for QemuExecutor<'a, CM, EH, H, OT,
where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&S::Input) -> ExitKind,
H: FnMut(&mut Emulator<CM, EH, ET, S>, &S::Input) -> ExitKind,
S: Unpin + State + HasExecutions,
OT: ObserversTuple<S>,
ET: EmulatorModuleTuple<S>,
@ -378,7 +297,7 @@ where
Z: UsesState<State = S>,
{
inner: InProcessForkExecutor<'a, H, OT, S, SP, EM, Z>,
state: QemuExecutorState<'a, CM, EH, ET, S>,
emulator: Emulator<CM, EH, ET, S>,
}
#[cfg(feature = "fork")]
@ -397,8 +316,8 @@ where
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("QemuForkExecutor")
.field("emulator", &self.state.emulator)
.field("inner", &self.inner)
.field("emulator", &self.emulator)
.finish()
}
}
@ -419,7 +338,7 @@ where
Z: HasObjective<Objective = OF, State = S>,
{
pub fn new(
emulator: &'a mut Emulator<CM, EH, ET, S>,
emulator: Emulator<CM, EH, ET, S>,
harness_fn: &'a mut H,
observers: OT,
fuzzer: &mut Z,
@ -440,7 +359,7 @@ where
timeout,
shmem_provider,
)?,
state: QemuExecutorState { emulator },
emulator,
})
}
@ -453,7 +372,11 @@ where
}
pub fn emulator(&self) -> &Emulator<CM, EH, ET, S> {
self.state.emulator
&self.emulator
}
pub fn emulator_mut(&mut self) -> &Emulator<CM, EH, ET, S> {
&mut self.emulator
}
}

View File

@ -1,217 +0,0 @@
//! A `QEMU`-based executor for binary-only instrumentation in `LibAFL`
use core::{
ffi::c_void,
fmt::{self, Debug, Formatter},
time::Duration,
};
use libafl::{
events::{EventFirer, EventRestarter},
executors::{
inprocess::{stateful::StatefulInProcessExecutor, HasInProcessHooks},
Executor, ExitKind, HasObservers,
},
feedbacks::Feedback,
fuzzer::HasObjective,
observers::{ObserversTuple, UsesObservers},
state::{HasCorpus, HasExecutions, HasSolutions, State, UsesState},
Error, ExecutionProcessor, HasScheduler,
};
use libafl_bolts::tuples::RefIndexable;
#[cfg(emulation_mode = "usermode")]
use crate::executor::inproc_qemu_crash_handler;
#[cfg(emulation_mode = "systemmode")]
use crate::executor::{inproc_qemu_timeout_handler, BREAK_ON_TMOUT};
use crate::{
command::CommandManager, executor::QemuExecutorState, modules::EmulatorModuleTuple, Emulator,
EmulatorExitHandler,
};
pub struct StatefulQemuExecutor<'a, CM, EH, H, OT, ET, S>
where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&S::Input, &mut QemuExecutorState<'a, CM, EH, ET, S>) -> ExitKind,
S: Unpin + State + HasExecutions,
OT: ObserversTuple<S>,
ET: EmulatorModuleTuple<S>,
{
inner: StatefulInProcessExecutor<'a, H, OT, S, QemuExecutorState<'a, CM, EH, ET, S>>,
}
impl<'a, CM, EH, H, OT, ET, S> Debug for StatefulQemuExecutor<'a, CM, EH, H, OT, ET, S>
where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&S::Input, &mut QemuExecutorState<'a, CM, EH, ET, S>) -> ExitKind,
S: Unpin + State + HasExecutions,
OT: ObserversTuple<S> + Debug,
ET: EmulatorModuleTuple<S> + Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("StatefulQemuExecutor")
.field("inner", &self.inner)
.finish()
}
}
impl<'a, CM, EH, H, OT, ET, S> StatefulQemuExecutor<'a, CM, EH, H, OT, ET, S>
where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&S::Input, &mut QemuExecutorState<'a, CM, EH, ET, S>) -> ExitKind,
S: Unpin + State + HasExecutions,
OT: ObserversTuple<S>,
ET: EmulatorModuleTuple<S> + Debug,
{
pub fn new<EM, OF, Z>(
emulator: &'a mut Emulator<CM, EH, ET, S>,
harness_fn: &'a mut H,
observers: OT,
fuzzer: &mut Z,
state: &mut S,
event_mgr: &mut EM,
timeout: Duration,
) -> Result<Self, Error>
where
EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<S>,
S: Unpin + State + HasExecutions + HasCorpus + HasSolutions,
Z: HasObjective<Objective = OF, State = S> + HasScheduler + ExecutionProcessor,
{
let qemu_state = QemuExecutorState::new::<
StatefulInProcessExecutor<'a, H, OT, S, QemuExecutorState<'a, CM, EH, ET, S>>,
EM,
OF,
OT,
Z,
>(emulator)?;
let mut inner = StatefulInProcessExecutor::with_timeout(
harness_fn, qemu_state, observers, fuzzer, state, event_mgr, timeout,
)?;
#[cfg(emulation_mode = "usermode")]
{
inner.inprocess_hooks_mut().crash_handler = inproc_qemu_crash_handler::<
StatefulInProcessExecutor<'a, H, OT, S, QemuExecutorState<'a, CM, EH, ET, S>>,
EM,
OF,
Z,
ET,
S,
> as *const c_void;
}
#[cfg(emulation_mode = "systemmode")]
{
inner.inprocess_hooks_mut().timeout_handler = inproc_qemu_timeout_handler::<
StatefulInProcessExecutor<'a, H, OT, S, QemuExecutorState<'a, CM, EH, ET, S>>,
EM,
OF,
Z,
> as *const c_void;
}
Ok(Self { inner })
}
pub fn inner(
&self,
) -> &StatefulInProcessExecutor<'a, H, OT, S, QemuExecutorState<'a, CM, EH, ET, S>> {
&self.inner
}
#[cfg(emulation_mode = "systemmode")]
pub fn break_on_timeout(&mut self) {
unsafe {
BREAK_ON_TMOUT = true;
}
}
pub fn inner_mut(
&mut self,
) -> &mut StatefulInProcessExecutor<'a, H, OT, S, QemuExecutorState<'a, CM, EH, ET, S>> {
&mut self.inner
}
}
impl<'a, CM, EH, EM, H, OT, OF, ET, S, Z> Executor<EM, Z>
for StatefulQemuExecutor<'a, CM, EH, H, OT, ET, S>
where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
H: FnMut(&S::Input, &mut QemuExecutorState<'a, CM, EH, ET, S>) -> ExitKind,
S: Unpin + State + HasExecutions + HasCorpus + HasSolutions,
OT: ObserversTuple<S>,
OF: Feedback<S>,
ET: EmulatorModuleTuple<S> + Debug,
Z: HasObjective<Objective = OF, State = S>,
{
fn run_target(
&mut self,
fuzzer: &mut Z,
state: &mut Self::State,
mgr: &mut EM,
input: &Self::Input,
) -> Result<ExitKind, Error> {
self.inner
.exposed_executor_state_mut()
.pre_exec::<Self, EM, OF, Z>(input);
let mut exit_kind = self.inner.run_target(fuzzer, state, mgr, input)?;
self.inner
.exposed_executor_state
.post_exec::<Self, EM, OT, OF, Z>(
input,
&mut *self.inner.inner.observers_mut(),
&mut exit_kind,
);
Ok(exit_kind)
}
}
impl<'a, CM, EH, H, OT, ET, S> UsesState for StatefulQemuExecutor<'a, CM, EH, H, OT, ET, S>
where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&S::Input, &mut QemuExecutorState<'a, CM, EH, ET, S>) -> ExitKind,
OT: ObserversTuple<S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{
type State = S;
}
impl<'a, CM, EH, H, OT, ET, S> UsesObservers for StatefulQemuExecutor<'a, CM, EH, H, OT, ET, S>
where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&S::Input, &mut QemuExecutorState<'a, CM, EH, ET, S>) -> ExitKind,
OT: ObserversTuple<S>,
ET: EmulatorModuleTuple<S>,
S: Unpin + State + HasExecutions,
{
type Observers = OT;
}
impl<'a, CM, EH, H, OT, ET, S> HasObservers for StatefulQemuExecutor<'a, CM, EH, H, OT, ET, S>
where
CM: CommandManager<EH, ET, S>,
EH: EmulatorExitHandler<ET, S>,
H: FnMut(&S::Input, &mut QemuExecutorState<'a, CM, EH, ET, S>) -> ExitKind,
S: Unpin + State + HasExecutions,
OT: ObserversTuple<S>,
ET: EmulatorModuleTuple<S>,
{
#[inline]
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
self.inner.observers()
}
#[inline]
fn observers_mut(&mut self) -> RefIndexable<&mut Self::Observers, Self::Observers> {
self.inner.observers_mut()
}
}

View File

@ -218,13 +218,6 @@ where
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
// The wrapped harness function, calling out to the LLVM-style harness
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
harness_bytes(buf);
ExitKind::Ok
};
if self.use_cmplog.unwrap_or(false) {
let modules = {
#[cfg(not(any(feature = "mips", feature = "hexagon")))]
@ -237,7 +230,14 @@ where
}
};
let mut emulator = Emulator::new_with_qemu(
let mut harness = |_emulator: &mut Emulator<_, _, _, _>, input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
harness_bytes(buf);
ExitKind::Ok
};
let emulator = Emulator::new_with_qemu(
qemu,
modules,
NopEmulatorExitHandler,
@ -245,7 +245,7 @@ where
)?;
let executor = QemuExecutor::new(
&mut emulator,
emulator,
&mut harness,
tuple_list!(edges_observer, time_observer),
&mut fuzzer,
@ -347,7 +347,14 @@ where
} else {
let tools = tuple_list!(EdgeCoverageModule::default());
let mut emulator = Emulator::new_with_qemu(
let mut harness = |_emulator: &mut Emulator<_, _, _, _>, input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
harness_bytes(buf);
ExitKind::Ok
};
let emulator = Emulator::new_with_qemu(
qemu,
tools,
NopEmulatorExitHandler,
@ -355,7 +362,7 @@ where
)?;
let mut executor = QemuExecutor::new(
&mut emulator,
emulator,
&mut harness,
tuple_list!(edges_observer, time_observer),
&mut fuzzer,