Remove UsesInput from libafl qemu (#2832)

* remove UsesInput from libafl_qemu

* Insert I bound instead of ugly Corpus::Input stuff

* Uses a C generic for Commands

* adapt nyx api to new generics

* add qemu linux fuzzers to CI for building.
This commit is contained in:
Romain Malmain 2025-01-14 10:24:28 +01:00 committed by GitHub
parent 8adb2aa7b5
commit a45e44764f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
58 changed files with 1924 additions and 2062 deletions

View File

@ -360,8 +360,8 @@ jobs:
# Full-system
- ./fuzzers/full_system/qemu_baremetal
# - ./fuzzers/full_system/qemu_linux_kernel
#- ./fuzzers/full_system/qemu_linux_process
- ./fuzzers/full_system/qemu_linux_kernel
- ./fuzzers/full_system/qemu_linux_process
runs-on: [ self-hosted, qemu ]
container: registry.gitlab.com/qemu-project/qemu/qemu/ubuntu2204:latest

View File

@ -327,7 +327,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 = |_emulator: &mut Emulator<_, _, _, _, _>, 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();

View File

@ -345,7 +345,7 @@ fn fuzz(
// The wrapped harness function, calling out to the LLVM-style harness
let mut harness =
|_emulator: &mut Emulator<_, _, _, _, _>, _state: &mut _, input: &BytesInput| {
|_emulator: &mut Emulator<_, _, _, _, _, _, _>, _state: &mut _, input: &BytesInput| {
let target = input.target_bytes();
let mut buf = target.as_slice();
let mut len = buf.len();

View File

@ -122,8 +122,8 @@ pub fn main() {
}
.build();
type PTInProcessExecutor<'a, H, OT, S, T> =
GenericInProcessExecutor<H, &'a mut H, (IntelPTHook<T>, ()), OT, S>;
type PTInProcessExecutor<'a, H, I, OT, S, T> =
GenericInProcessExecutor<H, &'a mut H, (IntelPTHook<T>, ()), I, OT, S>;
// Create the executor for an in-process function with just one observer
let mut executor = PTInProcessExecutor::with_timeout_generic(
tuple_list!(pt_hook),

View File

@ -197,7 +197,7 @@ pub fn fuzz() -> Result<(), Error> {
let scheduler = QueueScheduler::new();
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
let mut harness = |_emulator: &mut Emulator<_, _, _, _, _>, 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();

View File

@ -197,7 +197,7 @@ pub fn fuzz() {
};
let mut harness =
|_emulator: &mut Emulator<_, _, _, _, _>, _state: &mut _, input: &BytesInput| {
|_emulator: &mut Emulator<_, _, _, _, _, _, _>, _state: &mut _, input: &BytesInput| {
let target = input.target_bytes();
let mut buf = target.as_slice();
let mut len = buf.len();

View File

@ -26,7 +26,7 @@ use libafl::{
calibrate::CalibrationStage, power::StdPowerMutationalStage, AflStatsStage, IfStage,
ShadowTracingStage, StagesTuple, StdMutationalStage,
},
state::{HasCorpus, StdState, UsesState},
state::{HasCorpus, StdState},
Error, HasMetadata, NopFuzzer,
};
#[cfg(not(feature = "simplemgr"))]
@ -113,7 +113,7 @@ impl<M: Monitor> Instance<'_, M> {
state: Option<ClientState>,
) -> Result<(), Error>
where
ET: EmulatorModuleTuple<ClientState> + Debug,
ET: EmulatorModuleTuple<BytesInput, ClientState> + Debug,
{
// Create an observation channel using the coverage map
let mut edges_observer = unsafe {
@ -138,7 +138,7 @@ impl<M: Monitor> Instance<'_, M> {
let qemu = emulator.qemu();
// update address filter after qemu has been initialized
<EdgeCoverageModule<StdAddressFilter, NopPageFilter, EdgeCoverageFullVariant, false, 0> as EmulatorModule<ClientState>>::update_address_filter(emulator.modules_mut()
<EdgeCoverageModule<StdAddressFilter, NopPageFilter, EdgeCoverageFullVariant, false, 0> as EmulatorModule<BytesInput, ClientState>>::update_address_filter(emulator.modules_mut()
.modules_mut()
.match_first_type_mut::<EdgeCoverageModule<StdAddressFilter, NopPageFilter, EdgeCoverageFullVariant, false, 0>>()
.expect("Could not find back the edge module"), qemu, self.coverage_filter(qemu)?);
@ -216,7 +216,7 @@ impl<M: Monitor> Instance<'_, M> {
harness.post_fork();
let mut harness = |_emulator: &mut Emulator<_, _, _, _, _>,
let mut harness = |_emulator: &mut Emulator<_, _, _, _, _, _, _>,
_state: &mut _,
input: &BytesInput| harness.run(input);

View File

@ -87,8 +87,9 @@ pub fn fuzz() {
let args: Vec<String> = env::args().collect();
// The wrapped harness function, calling out to the LLVM-style harness
let mut harness =
|emulator: &mut Emulator<_, _, _, _, _>, state: &mut _, input: &BytesInput| unsafe {
let mut harness = |emulator: &mut Emulator<_, _, _, _, _, _, _>,
state: &mut _,
input: &BytesInput| unsafe {
emulator.run(state, input).unwrap().try_into().unwrap()
};

View File

@ -146,7 +146,7 @@ pub fn fuzz() {
// The wrapped harness function, calling out to the LLVM-style harness
let mut harness =
|emulator: &mut Emulator<_, _, _, _, _>, _state: &mut _, input: &BytesInput| {
|emulator: &mut Emulator<_, _, _, _, _, _, _>, _state: &mut _, input: &BytesInput| {
let target = input.target_bytes();
let mut buf = target.as_slice();
let len = buf.len();

View File

@ -71,8 +71,9 @@ pub fn fuzz() {
println!("Devices = {:?}", devices);
// The wrapped harness function, calling out to the LLVM-style harness
let mut harness =
|emulator: &mut Emulator<_, _, _, _, _>, state: &mut _, input: &BytesInput| unsafe {
let mut harness = |emulator: &mut Emulator<_, _, _, _, _, _, _>,
state: &mut _,
input: &BytesInput| unsafe {
emulator.run(state, input).unwrap().try_into().unwrap()
};

View File

@ -138,6 +138,24 @@ ${TARGET_DIR}/${PROFILE_DIR}/qemu_linux_kernel \
-serial null
'''
[tasks.test_unix]
script_runner = "@shell"
script = '''
# TODO: Run real test, not only building.
# LibAFL QEMU API
HARNESS_API=lqemu cargo make build
# Nyx API
HARNESS_API=nyx cargo make build
'''
[tasks.test]
description = "Run a test"
linux_alias = "test_unix"
mac_alias = "test_unix"
windows_alias = "unsupported"
[tasks.debug]
dependencies = ["build"]
command = "time"

View File

@ -12,7 +12,7 @@ use libafl::{
feedback_or, feedback_or_fast,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
fuzzer::{Fuzzer, StdFuzzer},
inputs::{BytesInput, HasTargetBytes, UsesInput},
inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor,
mutators::{havoc_mutations, scheduled::StdScheduledMutator, I2SRandReplaceBinonly},
observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver},
@ -32,7 +32,10 @@ use libafl_bolts::{
#[cfg(feature = "nyx")]
use libafl_qemu::{command::nyx::NyxCommandManager, NyxEmulatorDriver};
#[cfg(not(feature = "nyx"))]
use libafl_qemu::{command::StdCommandManager, StdEmulatorDriver};
use libafl_qemu::{
command::StdCommandManager, modules::utils::filters::LINUX_PROCESS_ADDRESS_RANGE,
StdEmulatorDriver,
};
use libafl_qemu::{
emu::Emulator,
executor::QemuExecutor,
@ -45,17 +48,17 @@ use libafl_qemu::{
use libafl_targets::{edges_map_mut_ptr, EDGES_MAP_DEFAULT_SIZE, MAX_EDGES_FOUND};
#[cfg(feature = "nyx")]
fn get_emulator<ET, S>(
fn get_emulator<C, ET, I, S>(
args: Vec<String>,
modules: ET,
) -> Result<
Emulator<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, NopSnapshotManager>,
Emulator<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, NopSnapshotManager>,
QemuInitError,
>
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
<S as UsesInput>::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
{
Emulator::empty()
.qemu_parameters(args)
@ -67,17 +70,17 @@ where
}
#[cfg(not(feature = "nyx"))]
fn get_emulator<ET, S>(
fn get_emulator<C, ET, I, S>(
args: Vec<String>,
mut modules: ET,
) -> Result<
Emulator<StdCommandManager<S>, StdEmulatorDriver, ET, S, FastSnapshotManager>,
Emulator<C, StdCommandManager<S>, StdEmulatorDriver, ET, I, S, FastSnapshotManager>,
QemuInitError,
>
where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: State + HasExecutions + Unpin,
<S as UsesInput>::Input: HasTargetBytes,
{
// Allow linux process address space addresses as feedback
modules.allow_address_range_all(LINUX_PROCESS_ADDRESS_RANGE);
@ -146,8 +149,9 @@ pub fn fuzz() {
println!("Devices = {:?}", devices);
// The wrapped harness function, calling out to the LLVM-style harness
let mut harness =
|emulator: &mut Emulator<_, _, _, _, _>, state: &mut _, input: &BytesInput| unsafe {
let mut harness = |emulator: &mut Emulator<_, _, _, _, _, _, _>,
state: &mut _,
input: &BytesInput| unsafe {
emulator.run(state, input).unwrap().try_into().unwrap()
};

View File

@ -1,6 +1,6 @@
//! A systemmode linux kernel example
//!
#[cfg(all(target_os = "linux"))]
#[cfg(target_os = "linux")]
mod fuzzer;
#[cfg(target_os = "linux")]

View File

@ -135,6 +135,24 @@ args = [
"${FEATURE}",
]
[tasks.test_unix]
script_runner = "@shell"
script = '''
# TODO: Run real test, not only building.
# LibAFL QEMU API
HARNESS_API=lqemu cargo make build
# Nyx API
HARNESS_API=nyx cargo make build
'''
[tasks.test]
description = "Run a test"
linux_alias = "test_unix"
mac_alias = "test_unix"
windows_alias = "unsupported"
[tasks.run]
dependencies = ["build"]
script_runner = "@shell"

View File

@ -8,11 +8,11 @@ use libafl::state::{HasExecutions, State};
use libafl::{
corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus},
events::{launcher::Launcher, EventConfig},
executors::{ExitKind, ShadowExecutor},
executors::ShadowExecutor,
feedback_and_fast, feedback_or, feedback_or_fast,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
fuzzer::{Fuzzer, StdFuzzer},
inputs::{BytesInput, HasTargetBytes, UsesInput},
inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor,
mutators::{havoc_mutations, I2SRandReplaceBinonly, StdScheduledMutator},
observers::{CanTrack, HitcountsMapObserver, TimeObserver, VariableMapObserver},
@ -32,31 +32,33 @@ use libafl_bolts::{
#[cfg(feature = "nyx")]
use libafl_qemu::{command::nyx::NyxCommandManager, NyxEmulatorDriver};
#[cfg(not(feature = "nyx"))]
use libafl_qemu::{command::StdCommandManager, StdEmulatorDriver};
use libafl_qemu::{
command::StdCommandManager, modules::utils::filters::LINUX_PROCESS_ADDRESS_RANGE,
StdEmulatorDriver,
};
use libafl_qemu::{
emu::Emulator,
executor::QemuExecutor,
modules::{
cmplog::CmpLogObserver, edges::StdEdgeCoverageClassicModule,
utils::filters::LINUX_PROCESS_ADDRESS_RANGE, CmpLogModule, EmulatorModuleTuple,
cmplog::CmpLogObserver, edges::StdEdgeCoverageClassicModule, CmpLogModule,
EmulatorModuleTuple,
},
EmulatorDriverError, FastSnapshotManager, NopSnapshotManager, QemuInitError,
QemuSnapshotManager,
FastSnapshotManager, NopSnapshotManager, QemuInitError, QemuSnapshotManager,
};
use libafl_targets::{edges_map_mut_ptr, EDGES_MAP_DEFAULT_SIZE, MAX_EDGES_FOUND};
#[cfg(feature = "nyx")]
fn get_emulator<ET, S>(
fn get_emulator<C, ET, I, S>(
args: Vec<String>,
modules: ET,
) -> Result<
Emulator<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, NopSnapshotManager>,
Emulator<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, NopSnapshotManager>,
QemuInitError,
>
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
<S as UsesInput>::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
S: Unpin,
I: HasTargetBytes + Unpin,
{
Emulator::empty()
.qemu_parameters(args)
@ -68,17 +70,17 @@ where
}
#[cfg(not(feature = "nyx"))]
fn get_emulator<ET, S>(
fn get_emulator<C, ET, I, S>(
args: Vec<String>,
mut modules: ET,
) -> Result<
Emulator<StdCommandManager<S>, StdEmulatorDriver, ET, S, FastSnapshotManager>,
Emulator<C, StdCommandManager<S>, StdEmulatorDriver, ET, I, S, FastSnapshotManager>,
QemuInitError,
>
where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: State + HasExecutions + Unpin,
<S as UsesInput>::Input: HasTargetBytes,
{
// Allow linux process address space addresses as feedback
modules.allow_address_range_all(LINUX_PROCESS_ADDRESS_RANGE);
@ -145,8 +147,9 @@ pub fn fuzz() {
let emu = get_emulator(args, modules)?;
// The wrapped harness function, calling out to the LLVM-style harness
let mut harness =
|emulator: &mut Emulator<_, _, _, _, _>, state: &mut _, input: &BytesInput| unsafe {
let mut harness = |emulator: &mut Emulator<_, _, _, _, _, _, _>,
state: &mut _,
input: &BytesInput| unsafe {
match emulator.run(state, input) {
Ok(res) => res.try_into().unwrap(),
Err(e) => match e {

View File

@ -1,6 +1,6 @@
//! A systemmode linux kernel example
//!
#[cfg(all(target_os = "linux"))]
#[cfg(target_os = "linux")]
mod fuzzer;
#[cfg(target_os = "linux")]

View File

@ -24,20 +24,19 @@ use crate::executors::hooks::timer::TimerStruct;
#[cfg(all(unix, feature = "std"))]
use crate::executors::hooks::unix::unix_signal_handler;
#[cfg(any(unix, windows))]
use crate::observers::ObserversTuple;
use crate::{corpus::Corpus, inputs::Input, observers::ObserversTuple, state::HasCurrentTestcase};
use crate::{
corpus::Corpus,
events::{EventFirer, EventRestarter},
executors::{hooks::ExecutorHook, inprocess::HasInProcessHooks, Executor, HasObservers},
feedbacks::Feedback,
inputs::{Input, UsesInput},
state::{HasCorpus, HasCurrentTestcase, HasExecutions, HasSolutions},
inputs::UsesInput,
state::{HasCorpus, HasExecutions, HasSolutions},
Error, HasObjective,
};
/// The inmem executor's handlers.
#[expect(missing_debug_implementations)]
pub struct InProcessHooks<S> {
pub struct InProcessHooks<I, S> {
/// On crash C function pointer
#[cfg(feature = "std")]
pub crash_handler: *const c_void,
@ -47,7 +46,7 @@ pub struct InProcessHooks<S> {
/// `TImer` struct
#[cfg(feature = "std")]
pub timer: TimerStruct,
phantom: PhantomData<S>,
phantom: PhantomData<(I, S)>,
}
/// Any hooks that is about timeout
@ -83,7 +82,7 @@ pub trait HasTimeout {
fn handle_timeout(&mut self, data: &mut InProcessExecutorHandlerData) -> bool;
}
impl<S> HasTimeout for InProcessHooks<S> {
impl<I, S> HasTimeout for InProcessHooks<I, S> {
#[cfg(feature = "std")]
fn timer(&self) -> &TimerStruct {
&self.timer
@ -187,14 +186,13 @@ impl<S> HasTimeout for InProcessHooks<S> {
}
}
impl<S> ExecutorHook<<S::Corpus as Corpus>::Input, S> for InProcessHooks<S>
impl<I, S> ExecutorHook<I, S> for InProcessHooks<I, S>
where
S: HasCorpus,
{
fn init(&mut self, _state: &mut S) {}
/// Call before running a target.
#[expect(unused_variables)]
fn pre_exec(&mut self, state: &mut S, input: &<S::Corpus as Corpus>::Input) {
fn pre_exec(&mut self, _state: &mut S, _input: &I) {
#[cfg(feature = "std")]
unsafe {
let data = &raw mut GLOBAL_STATE;
@ -207,7 +205,7 @@ where
}
/// Call after running a target.
fn post_exec(&mut self, _state: &mut S, _input: &<S::Corpus as Corpus>::Input) {
fn post_exec(&mut self, _state: &mut S, _input: &I) {
// timeout stuff
// # Safety
// We're calling this only once per execution, in a single thread.
@ -216,24 +214,20 @@ where
}
}
impl<S> InProcessHooks<S> {
impl<I, S> InProcessHooks<I, S> {
/// Create new [`InProcessHooks`].
#[cfg(unix)]
#[allow(unused_variables)] // for `exec_tmout` without `std`
pub fn new<E, EM, OF, Z>(exec_tmout: Duration) -> Result<Self, Error>
where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers + HasInProcessHooks<S>,
E::Observers: ObserversTuple<<S as UsesInput>::Input, S>,
E: Executor<EM, I, S, Z> + HasObservers + HasInProcessHooks<I, S>,
E::Observers: ObserversTuple<I, S>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
S: HasExecutions
+ HasSolutions
+ HasCorpus
+ HasCurrentTestcase
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase + UsesInput<Input = I>,
Z: HasObjective<Objective = OF>,
<S::Corpus as Corpus>::Input: Input + Clone,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
I: Input + Clone,
S::Solutions: Corpus<Input = I>,
{
// # Safety
// We get a pointer to `GLOBAL_STATE` that will be initialized at this point in time.
@ -242,7 +236,7 @@ impl<S> InProcessHooks<S> {
#[cfg(all(not(miri), unix, feature = "std"))]
let data = unsafe { &raw mut GLOBAL_STATE };
#[cfg(feature = "std")]
unix_signal_handler::setup_panic_hook::<E, EM, OF, S, Z>();
unix_signal_handler::setup_panic_hook::<E, EM, I, OF, S, Z>();
// # Safety
// Setting up the signal handlers with a pointer to the `GLOBAL_STATE` which should not be NULL at this point.
// We are the sole users of `GLOBAL_STATE` right now, and only dereference it in case of Segfault/Panic.
@ -254,10 +248,10 @@ impl<S> InProcessHooks<S> {
compiler_fence(Ordering::SeqCst);
Ok(Self {
#[cfg(feature = "std")]
crash_handler: unix_signal_handler::inproc_crash_handler::<E, EM, OF, S, Z>
crash_handler: unix_signal_handler::inproc_crash_handler::<E, EM, I, OF, S, Z>
as *const c_void,
#[cfg(feature = "std")]
timeout_handler: unix_signal_handler::inproc_timeout_handler::<E, EM, OF, S, Z>
timeout_handler: unix_signal_handler::inproc_timeout_handler::<E, EM, I, OF, S, Z>
as *const _,
#[cfg(feature = "std")]
timer: TimerStruct::new(exec_tmout),
@ -270,18 +264,14 @@ impl<S> InProcessHooks<S> {
#[allow(unused_variables)] // for `exec_tmout` without `std`
pub fn new<E, EM, OF, Z>(exec_tmout: Duration) -> Result<Self, Error>
where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers + HasInProcessHooks<S>,
E::Observers: ObserversTuple<<S as UsesInput>::Input, S>,
E: Executor<EM, I, S, Z> + HasObservers + HasInProcessHooks<I, S>,
E::Observers: ObserversTuple<I, S>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
S: HasExecutions
+ HasSolutions
+ HasCorpus
+ HasCurrentTestcase
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
I: Input + Clone,
OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase + UsesInput<Input = I>,
S::Solutions: Corpus<Input = I>,
Z: HasObjective<Objective = OF>,
<S::Corpus as Corpus>::Input: Input + Clone,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
{
let ret;
#[cfg(feature = "std")]
@ -290,6 +280,7 @@ impl<S> InProcessHooks<S> {
crate::executors::hooks::windows::windows_exception_handler::setup_panic_hook::<
E,
EM,
I,
OF,
S,
Z,
@ -300,6 +291,7 @@ impl<S> InProcessHooks<S> {
crate::executors::hooks::windows::windows_exception_handler::inproc_crash_handler::<
E,
EM,
I,
OF,
S,
Z,
@ -308,6 +300,7 @@ impl<S> InProcessHooks<S> {
crate::executors::hooks::windows::windows_exception_handler::inproc_timeout_handler::<
E,
EM,
I,
OF,
S,
Z,
@ -335,13 +328,10 @@ impl<S> InProcessHooks<S> {
#[expect(unused_variables)]
pub fn new<E, EM, OF, Z>(exec_tmout: Duration) -> Result<Self, Error>
where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers + HasInProcessHooks<S>,
E: Executor<EM, I, S, Z> + HasObservers + HasInProcessHooks<I, S>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
S: HasExecutions
+ HasSolutions
+ HasCorpus
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCorpus + UsesInput<Input = I>,
Z: HasObjective<Objective = OF>,
{
#[cfg_attr(miri, allow(unused_variables))]

View File

@ -14,7 +14,6 @@ use libafl_bolts::os::unix_signals::{ucontext_t, Signal, SignalHandler};
use libc::siginfo_t;
use crate::{
corpus::Corpus,
executors::{
common_signals,
hooks::ExecutorHook,
@ -28,15 +27,15 @@ use crate::{
/// The inmem fork executor's hooks.
#[derive(Debug)]
pub struct InChildProcessHooks<S> {
pub struct InChildProcessHooks<I, S> {
/// On crash C function pointer
pub crash_handler: *const c_void,
/// On timeout C function pointer
pub timeout_handler: *const c_void,
phantom: PhantomData<S>,
phantom: PhantomData<(I, S)>,
}
impl<S> ExecutorHook<<S::Corpus as Corpus>::Input, S> for InChildProcessHooks<S>
impl<I, S> ExecutorHook<I, S> for InChildProcessHooks<I, S>
where
S: HasCorpus,
{
@ -44,7 +43,7 @@ where
fn init(&mut self, _state: &mut S) {}
/// Call before running a target.
fn pre_exec(&mut self, _state: &mut S, _input: &<S::Corpus as Corpus>::Input) {
fn pre_exec(&mut self, _state: &mut S, _input: &I) {
unsafe {
let data = &raw mut FORK_EXECUTOR_GLOBAL_DATA;
(*data).crash_handler = self.crash_handler;
@ -53,15 +52,15 @@ where
}
}
fn post_exec(&mut self, _state: &mut S, _input: &<S::Corpus as Corpus>::Input) {}
fn post_exec(&mut self, _state: &mut S, _input: &I) {}
}
impl<S> InChildProcessHooks<S> {
impl<I, S> InChildProcessHooks<I, S> {
/// Create new [`InChildProcessHooks`].
pub fn new<E>() -> Result<Self, Error>
where
E: HasObservers,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
E::Observers: ObserversTuple<I, S>,
S: HasCorpus,
{
#[cfg_attr(miri, allow(unused_variables, unused_unsafe))]
@ -72,16 +71,10 @@ impl<S> InChildProcessHooks<S> {
setup_signal_handler(data)?;
compiler_fence(Ordering::SeqCst);
Ok(Self {
crash_handler: child_signal_handlers::child_crash_handler::<
E,
<S::Corpus as Corpus>::Input,
S,
> as *const c_void,
timeout_handler: child_signal_handlers::child_timeout_handler::<
E,
<S::Corpus as Corpus>::Input,
S,
> as *const c_void,
crash_handler: child_signal_handlers::child_crash_handler::<E, I, S>
as *const c_void,
timeout_handler: child_signal_handlers::child_timeout_handler::<E, I, S>
as *const c_void,
phantom: PhantomData,
})
}

View File

@ -77,20 +77,16 @@ pub mod unix_signal_handler {
}
/// invokes the `post_exec` hook on all observer in case of panic
pub fn setup_panic_hook<E, EM, OF, S, Z>()
pub fn setup_panic_hook<E, EM, I, OF, S, Z>()
where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
E: Executor<EM, I, S, Z> + HasObservers,
E::Observers: ObserversTuple<I, S>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
S: HasExecutions
+ HasSolutions
+ HasCurrentTestcase
+ HasCorpus
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCurrentTestcase + HasCorpus + UsesInput<Input = I>,
S::Solutions: Corpus<Input = I>,
Z: HasObjective<Objective = OF>,
<S::Corpus as Corpus>::Input: Input + Clone,
I: Input + Clone,
{
let old_hook = panic::take_hook();
panic::set_hook(Box::new(move |panic_info| unsafe {
@ -101,11 +97,11 @@ pub mod unix_signal_handler {
// We are fuzzing!
let executor = (*data).executor_mut::<E>();
let state = (*data).state_mut::<S>();
let input = (*data).take_current_input::<<S::Corpus as Corpus>::Input>();
let input = (*data).take_current_input::<I>();
let fuzzer = (*data).fuzzer_mut::<Z>();
let event_mgr = (*data).event_mgr_mut::<EM>();
run_observers_and_save_state::<E, EM, OF, S, Z>(
run_observers_and_save_state::<E, EM, I, OF, S, Z>(
executor,
state,
input,
@ -127,24 +123,20 @@ pub mod unix_signal_handler {
/// Well, signal handling is not safe
#[cfg(unix)]
#[allow(clippy::needless_pass_by_value)] // nightly no longer requires this
pub unsafe fn inproc_timeout_handler<E, EM, OF, S, Z>(
pub unsafe fn inproc_timeout_handler<E, EM, I, OF, S, Z>(
_signal: Signal,
_info: &mut siginfo_t,
_context: Option<&mut ucontext_t>,
data: &mut InProcessExecutorHandlerData,
) where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasInProcessHooks<S> + HasObservers,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
E: Executor<EM, I, S, Z> + HasInProcessHooks<I, S> + HasObservers,
E::Observers: ObserversTuple<I, S>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
S: HasExecutions
+ HasSolutions
+ HasCurrentTestcase
+ HasCorpus
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCurrentTestcase + HasCorpus + UsesInput<Input = I>,
Z: HasObjective<Objective = OF>,
<S::Corpus as Corpus>::Input: Input + Clone,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
I: Input + Clone,
S::Solutions: Corpus<Input = I>,
{
// this stuff is for batch timeout
if !data.executor_ptr.is_null()
@ -165,11 +157,11 @@ pub mod unix_signal_handler {
let state = data.state_mut::<S>();
let event_mgr = data.event_mgr_mut::<EM>();
let fuzzer = data.fuzzer_mut::<Z>();
let input = data.take_current_input::<<S::Corpus as Corpus>::Input>();
let input = data.take_current_input::<I>();
log::error!("Timeout in fuzz run.");
run_observers_and_save_state::<E, EM, OF, S, Z>(
run_observers_and_save_state::<E, EM, I, OF, S, Z>(
executor,
state,
input,
@ -188,24 +180,20 @@ pub mod unix_signal_handler {
/// # Safety
/// Well, signal handling is not safe
#[allow(clippy::needless_pass_by_value)] // nightly no longer requires this
pub unsafe fn inproc_crash_handler<E, EM, OF, S, Z>(
pub unsafe fn inproc_crash_handler<E, EM, I, OF, S, Z>(
signal: Signal,
_info: &mut siginfo_t,
_context: Option<&mut ucontext_t>,
data: &mut InProcessExecutorHandlerData,
) where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
E: Executor<EM, I, S, Z> + HasObservers,
E::Observers: ObserversTuple<I, S>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
S: HasExecutions
+ HasSolutions
+ HasCorpus
+ HasCurrentTestcase
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase + UsesInput<Input = I>,
Z: HasObjective<Objective = OF>,
<S::Corpus as Corpus>::Input: Input + Clone,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
I: Input + Clone,
S::Solutions: Corpus<Input = I>,
{
#[cfg(all(target_os = "android", target_arch = "aarch64"))]
let _context = _context.map(|p| {
@ -220,7 +208,7 @@ pub mod unix_signal_handler {
let state = data.state_mut::<S>();
let event_mgr = data.event_mgr_mut::<EM>();
let fuzzer = data.fuzzer_mut::<Z>();
let input = data.take_current_input::<<S::Corpus as Corpus>::Input>();
let input = data.take_current_input::<I>();
log::error!("Child crashed!");
@ -245,7 +233,7 @@ pub mod unix_signal_handler {
}
}
run_observers_and_save_state::<E, EM, OF, S, Z>(
run_observers_and_save_state::<E, EM, I, OF, S, Z>(
executor,
state,
input,

View File

@ -24,20 +24,16 @@ pub mod windows_asan_handler {
/// # Safety
/// ASAN deatch handler
pub unsafe extern "C" fn asan_death_handler<E, EM, OF, S, Z>()
pub unsafe extern "C" fn asan_death_handler<E, EM, I, OF, S, Z>()
where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
E: Executor<EM, I, S, Z> + HasObservers,
E::Observers: ObserversTuple<I, S>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
S: HasExecutions
+ HasSolutions
+ HasCurrentTestcase
+ HasCorpus
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
I: Input + Clone,
OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCurrentTestcase + HasCorpus + UsesInput<Input = I>,
S::Solutions: Corpus<Input = I>,
Z: HasObjective<Objective = OF>,
<S::Corpus as Corpus>::Input: Input + Clone,
{
let data = &raw mut GLOBAL_STATE;
(*data).set_in_handler(true);
@ -89,9 +85,9 @@ pub mod windows_asan_handler {
log::error!("Child crashed!");
// Make sure we don't crash in the crash handler forever.
let input = (*data).take_current_input::<<S::Corpus as Corpus>::Input>();
let input = (*data).take_current_input::<I>();
run_observers_and_save_state::<E, EM, OF, S, Z>(
run_observers_and_save_state::<E, EM, I, OF, S, Z>(
executor,
state,
input,
@ -186,20 +182,16 @@ pub mod windows_exception_handler {
/// # Safety
/// Well, exception handling is not safe
#[cfg(feature = "std")]
pub fn setup_panic_hook<E, EM, OF, S, Z>()
pub fn setup_panic_hook<E, EM, I, OF, S, Z>()
where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
E: Executor<EM, I, S, Z> + HasObservers,
E::Observers: ObserversTuple<I, S>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
S: HasExecutions
+ HasSolutions
+ HasCurrentTestcase
+ HasCorpus
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
I: Input + Clone,
OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCurrentTestcase + HasCorpus + UsesInput<Input = I>,
S::Solutions: Corpus<Input = I>,
Z: HasObjective<Objective = OF>,
<S::Corpus as Corpus>::Input: Input + Clone,
{
let old_hook = panic::take_hook();
panic::set_hook(Box::new(move |panic_info| unsafe {
@ -228,9 +220,9 @@ pub mod windows_exception_handler {
let fuzzer = (*data).fuzzer_mut::<Z>();
let event_mgr = (*data).event_mgr_mut::<EM>();
let input = (*data).take_current_input::<<S::Corpus as Corpus>::Input>();
let input = (*data).take_current_input::<I>();
run_observers_and_save_state::<E, EM, OF, S, Z>(
run_observers_and_save_state::<E, EM, I, OF, S, Z>(
executor,
state,
input,
@ -250,23 +242,19 @@ pub mod windows_exception_handler {
///
/// # Safety
/// Well, exception handling is not safe
pub unsafe extern "system" fn inproc_timeout_handler<E, EM, OF, S, Z>(
pub unsafe extern "system" fn inproc_timeout_handler<E, EM, I, OF, S, Z>(
_p0: *mut u8,
global_state: *mut c_void,
_p1: *mut u8,
) where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasInProcessHooks<S> + HasObservers,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
E: Executor<EM, I, S, Z> + HasInProcessHooks<I, S> + HasObservers,
E::Observers: ObserversTuple<I, S>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
S: HasExecutions
+ HasSolutions
+ HasCurrentTestcase
+ HasCorpus
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
I: Input + Clone,
OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCurrentTestcase + HasCorpus + UsesInput<Input = I>,
Z: HasObjective<Objective = OF>,
<S::Corpus as Corpus>::Input: Input + Clone,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
S::Solutions: Corpus<Input = I>,
{
let data: &mut InProcessExecutorHandlerData =
&mut *(global_state as *mut InProcessExecutorHandlerData);
@ -298,12 +286,10 @@ pub mod windows_exception_handler {
} else {
log::error!("Timeout in fuzz run.");
let input = (data.current_input_ptr as *const <S::Corpus as Corpus>::Input)
.as_ref()
.unwrap();
let input = (data.current_input_ptr as *const I).as_ref().unwrap();
data.current_input_ptr = ptr::null_mut();
run_observers_and_save_state::<E, EM, OF, S, Z>(
run_observers_and_save_state::<E, EM, I, OF, S, Z>(
executor,
state,
input,
@ -327,22 +313,18 @@ pub mod windows_exception_handler {
///
/// # Safety
/// Well, exception handling is not safe
pub unsafe fn inproc_crash_handler<E, EM, OF, S, Z>(
pub unsafe fn inproc_crash_handler<E, EM, I, OF, S, Z>(
exception_pointers: *mut EXCEPTION_POINTERS,
data: &mut InProcessExecutorHandlerData,
) where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
E: Executor<EM, I, S, Z> + HasObservers,
E::Observers: ObserversTuple<I, S>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
S: HasExecutions
+ HasSolutions
+ HasCorpus
+ HasCurrentTestcase
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
I: Input + Clone,
OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase + UsesInput<Input = I>,
Z: HasObjective<Objective = OF>,
<S::Corpus as Corpus>::Input: Input + Clone,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
S::Solutions: Corpus<Input = I>,
{
// Have we set a timer_before?
if data.ptp_timer.is_some() {
@ -428,7 +410,7 @@ pub mod windows_exception_handler {
// Make sure we don't crash in the crash handler forever.
if is_crash {
let input = data.take_current_input::<<S::Corpus as Corpus>::Input>();
let input = data.take_current_input::<I>();
{
let mut bsod = Vec::new();
{
@ -440,7 +422,7 @@ pub mod windows_exception_handler {
}
log::error!("{}", std::str::from_utf8(&bsod).unwrap());
}
run_observers_and_save_state::<E, EM, OF, S, Z>(
run_observers_and_save_state::<E, EM, I, OF, S, Z>(
executor,
state,
input,

View File

@ -1,7 +1,6 @@
use core::{
ffi::c_void,
fmt::{self, Debug, Formatter},
marker::PhantomData,
ptr::{self, null, write_volatile},
sync::atomic::{compiler_fence, Ordering},
time::Duration,
@ -35,15 +34,14 @@ use crate::{
};
/// The internal state of `GenericInProcessExecutor`.
pub struct GenericInProcessExecutorInner<HT, OT, S> {
pub struct GenericInProcessExecutorInner<HT, I, OT, S> {
/// The observers, observing each run
pub(super) observers: OT,
// Crash and timeout hah
pub(super) hooks: (InProcessHooks<S>, HT),
phantom: PhantomData<S>,
pub(super) hooks: (InProcessHooks<I, S>, HT),
}
impl<HT, OT, S> Debug for GenericInProcessExecutorInner<HT, OT, S>
impl<HT, I, OT, S> Debug for GenericInProcessExecutorInner<HT, I, OT, S>
where
OT: Debug,
{
@ -54,7 +52,7 @@ where
}
}
impl<HT, OT, S> HasObservers for GenericInProcessExecutorInner<HT, OT, S> {
impl<HT, I, OT, S> HasObservers for GenericInProcessExecutorInner<HT, I, OT, S> {
type Observers = OT;
#[inline]
@ -68,9 +66,9 @@ impl<HT, OT, S> HasObservers for GenericInProcessExecutorInner<HT, OT, S> {
}
}
impl<HT, OT, S> GenericInProcessExecutorInner<HT, OT, S>
impl<HT, I, OT, S> GenericInProcessExecutorInner<HT, I, OT, S>
where
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
OT: ObserversTuple<I, S>,
S: HasCorpus,
{
/// This function marks the boundary between the fuzzer and the target
@ -84,7 +82,7 @@ where
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &<S::Corpus as Corpus>::Input,
input: &I,
executor_ptr: *const c_void,
) {
unsafe {
@ -119,7 +117,7 @@ where
_fuzzer: &mut Z,
_state: &mut S,
_mgr: &mut EM,
_input: &<S::Corpus as Corpus>::Input,
_input: &I,
) {
unsafe {
let data = &raw mut GLOBAL_STATE;
@ -130,10 +128,10 @@ where
}
}
impl<HT, OT, S> GenericInProcessExecutorInner<HT, OT, S>
impl<HT, I, OT, S> GenericInProcessExecutorInner<HT, I, OT, S>
where
HT: ExecutorHooksTuple<<S::Corpus as Corpus>::Input, S>,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
HT: ExecutorHooksTuple<I, S>,
OT: ObserversTuple<I, S>,
S: HasCorpus + HasExecutions + HasSolutions,
{
/// Create a new in mem executor with the default timeout (5 sec)
@ -145,17 +143,14 @@ where
event_mgr: &mut EM,
) -> Result<Self, Error>
where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers + HasInProcessHooks<S>,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
E: Executor<EM, I, S, Z> + HasObservers + HasInProcessHooks<I, S>,
E::Observers: ObserversTuple<I, S>,
EM: EventFirer<State = S> + EventRestarter,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
S: HasCurrentTestcase
+ HasCorpus
+ HasSolutions
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
I: Input + Clone,
OF: Feedback<EM, I, E::Observers, S>,
S: HasCurrentTestcase + HasCorpus + HasSolutions + UsesInput<Input = I>,
S::Solutions: Corpus<Input = I>,
Z: HasObjective<Objective = OF>,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
<S::Corpus as Corpus>::Input: Input + Clone,
{
Self::with_timeout_generic::<E, EM, OF, Z>(
user_hooks,
@ -178,17 +173,14 @@ where
exec_tmout: Duration,
) -> Result<Self, Error>
where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers + HasInProcessHooks<S>,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
E: Executor<EM, I, S, Z> + HasObservers + HasInProcessHooks<I, S>,
E::Observers: ObserversTuple<I, S>,
EM: EventFirer<State = S> + EventRestarter,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
S: HasCurrentTestcase
+ HasCorpus
+ HasSolutions
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
I: Input + Clone,
OF: Feedback<EM, I, E::Observers, S>,
S: HasCurrentTestcase + HasCorpus + HasSolutions + UsesInput<Input = I>,
S::Solutions: Corpus<Input = I>,
Z: HasObjective<Objective = OF>,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
<S::Corpus as Corpus>::Input: Input + Clone,
{
let mut me = Self::with_timeout_generic::<E, EM, OF, Z>(
user_hooks, observers, fuzzer, state, event_mgr, exec_tmout,
@ -214,17 +206,14 @@ where
timeout: Duration,
) -> Result<Self, Error>
where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers + HasInProcessHooks<S>,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
E: Executor<EM, I, S, Z> + HasObservers + HasInProcessHooks<I, S>,
E::Observers: ObserversTuple<I, S>,
EM: EventFirer<State = S> + EventRestarter,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
S: HasCurrentTestcase
+ HasCorpus
+ HasSolutions
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
OF: Feedback<EM, I, E::Observers, S>,
S: HasCurrentTestcase + HasCorpus + HasSolutions + UsesInput<Input = I>,
Z: HasObjective<Objective = OF>,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
<S::Corpus as Corpus>::Input: Input + Clone,
S::Solutions: Corpus<Input = I>,
I: Input + Clone,
{
let default = InProcessHooks::new::<E, EM, OF, Z>(timeout)?;
let mut hooks = tuple_list!(default).merge(user_hooks);
@ -253,36 +242,32 @@ where
*hooks.0.millis_sec_mut() = timeout.as_millis() as i64;
}
Ok(Self {
observers,
hooks,
phantom: PhantomData,
})
Ok(Self { observers, hooks })
}
/// The inprocess handlers
#[inline]
pub fn hooks(&self) -> &(InProcessHooks<S>, HT) {
pub fn hooks(&self) -> &(InProcessHooks<I, S>, HT) {
&self.hooks
}
/// The inprocess handlers (mutable)
#[inline]
pub fn hooks_mut(&mut self) -> &mut (InProcessHooks<S>, HT) {
pub fn hooks_mut(&mut self) -> &mut (InProcessHooks<I, S>, HT) {
&mut self.hooks
}
}
impl<HT, OT, S> HasInProcessHooks<S> for GenericInProcessExecutorInner<HT, OT, S> {
impl<HT, I, OT, S> HasInProcessHooks<I, S> for GenericInProcessExecutorInner<HT, I, OT, S> {
/// the timeout handler
#[inline]
fn inprocess_hooks(&self) -> &InProcessHooks<S> {
fn inprocess_hooks(&self) -> &InProcessHooks<I, S> {
&self.hooks.0
}
/// the timeout handler
#[inline]
fn inprocess_hooks_mut(&mut self) -> &mut InProcessHooks<S> {
fn inprocess_hooks_mut(&mut self) -> &mut InProcessHooks<I, S> {
&mut self.hooks.0
}
}

View File

@ -40,28 +40,29 @@ pub mod inner;
pub mod stateful;
/// The process executor simply calls a target function, as mutable reference to a closure.
pub type InProcessExecutor<'a, H, OT, S> = GenericInProcessExecutor<H, &'a mut H, (), OT, S>;
pub type InProcessExecutor<'a, H, I, OT, S> = GenericInProcessExecutor<H, &'a mut H, (), I, OT, S>;
/// The inprocess executor that allows hooks
pub type HookableInProcessExecutor<'a, H, HT, OT, S> =
GenericInProcessExecutor<H, &'a mut H, HT, OT, S>;
pub type HookableInProcessExecutor<'a, H, HT, I, OT, S> =
GenericInProcessExecutor<H, &'a mut H, HT, I, OT, S>;
/// The process executor simply calls a target function, as boxed `FnMut` trait object
pub type OwnedInProcessExecutor<OT, S> = GenericInProcessExecutor<
dyn FnMut(&<S as UsesInput>::Input) -> ExitKind,
Box<dyn FnMut(&<S as UsesInput>::Input) -> ExitKind>,
pub type OwnedInProcessExecutor<I, OT, S> = GenericInProcessExecutor<
dyn FnMut(&I) -> ExitKind,
Box<dyn FnMut(&I) -> ExitKind>,
(),
I,
OT,
S,
>;
/// The inmem executor simply calls a target function, then returns afterwards.
pub struct GenericInProcessExecutor<H, HB, HT, OT, S> {
pub struct GenericInProcessExecutor<H, HB, HT, I, OT, S> {
harness_fn: HB,
inner: GenericInProcessExecutorInner<HT, OT, S>,
inner: GenericInProcessExecutorInner<HT, I, OT, S>,
phantom: PhantomData<(*const H, HB)>,
}
impl<H, HB, HT, OT, S> Debug for GenericInProcessExecutor<H, HB, HT, OT, S>
impl<H, HB, HT, I, OT, S> Debug for GenericInProcessExecutor<H, HB, HT, I, OT, S>
where
OT: Debug,
{
@ -73,21 +74,21 @@ where
}
}
impl<EM, H, HB, HT, OT, S, Z> Executor<EM, <S::Corpus as Corpus>::Input, S, Z>
for GenericInProcessExecutor<H, HB, HT, OT, S>
impl<EM, H, HB, HT, I, OT, S, Z> Executor<EM, I, S, Z>
for GenericInProcessExecutor<H, HB, HT, I, OT, S>
where
S: HasCorpus + HasExecutions,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
HT: ExecutorHooksTuple<<S::Corpus as Corpus>::Input, S>,
OT: ObserversTuple<I, S>,
HT: ExecutorHooksTuple<I, S>,
HB: BorrowMut<H>,
H: FnMut(&<S::Corpus as Corpus>::Input) -> ExitKind + Sized,
H: FnMut(&I) -> ExitKind + Sized,
{
fn run_target(
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &<S::Corpus as Corpus>::Input,
input: &I,
) -> Result<ExitKind, Error> {
*state.executions_mut() += 1;
unsafe {
@ -105,7 +106,7 @@ where
}
}
impl<H, HB, HT, OT, S> HasObservers for GenericInProcessExecutor<H, HB, HT, OT, S> {
impl<H, HB, HT, I, OT, S> HasObservers for GenericInProcessExecutor<H, HB, HT, I, OT, S> {
type Observers = OT;
#[inline]
@ -119,17 +120,13 @@ impl<H, HB, HT, OT, S> HasObservers for GenericInProcessExecutor<H, HB, HT, OT,
}
}
impl<'a, H, OT, S> InProcessExecutor<'a, H, OT, S>
impl<'a, H, I, OT, S> InProcessExecutor<'a, H, I, OT, S>
where
H: FnMut(&<S::Corpus as Corpus>::Input) -> ExitKind + Sized,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
S: HasCorpus
+ HasCurrentTestcase
+ UsesInput<Input = <S::Corpus as Corpus>::Input>
+ HasExecutions
+ HasSolutions,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
<S::Corpus as Corpus>::Input: Input,
H: FnMut(&I) -> ExitKind + Sized,
OT: ObserversTuple<I, S>,
S: HasCorpus + HasCurrentTestcase + UsesInput<Input = I> + HasExecutions + HasSolutions,
S::Solutions: Corpus<Input = I>,
I: Input,
{
/// Create a new in mem executor with the default timeout (5 sec)
pub fn new<EM, OF, Z>(
@ -141,7 +138,7 @@ where
) -> Result<Self, Error>
where
EM: EventFirer<State = S> + EventRestarter,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, OT, S>,
OF: Feedback<EM, I, OT, S>,
Z: HasObjective<Objective = OF>,
{
Self::with_timeout_generic::<EM, OF, Z>(
@ -167,7 +164,7 @@ where
) -> Result<Self, Error>
where
EM: EventFirer<State = S> + EventRestarter,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, OT, S>,
OF: Feedback<EM, I, OT, S>,
Z: HasObjective<Objective = OF>,
{
let inner = GenericInProcessExecutorInner::batched_timeout_generic::<Self, EM, OF, Z>(
@ -204,7 +201,7 @@ where
) -> Result<Self, Error>
where
EM: EventFirer<State = S> + EventRestarter,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, OT, S>,
OF: Feedback<EM, I, OT, S>,
Z: HasObjective<Objective = OF>,
{
let inner = GenericInProcessExecutorInner::with_timeout_generic::<Self, EM, OF, Z>(
@ -224,19 +221,15 @@ where
}
}
impl<H, HB, HT, OT, S> GenericInProcessExecutor<H, HB, HT, OT, S>
impl<H, HB, HT, I, OT, S> GenericInProcessExecutor<H, HB, HT, I, OT, S>
where
H: FnMut(&<S::Corpus as Corpus>::Input) -> ExitKind + Sized,
H: FnMut(&I) -> ExitKind + Sized,
HB: BorrowMut<H>,
HT: ExecutorHooksTuple<<S::Corpus as Corpus>::Input, S>,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
S: HasCorpus
+ HasCurrentTestcase
+ UsesInput<Input = <S::Corpus as Corpus>::Input>
+ HasExecutions
+ HasSolutions,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
<S::Corpus as Corpus>::Input: Input,
HT: ExecutorHooksTuple<I, S>,
OT: ObserversTuple<I, S>,
S: HasCorpus + HasCurrentTestcase + UsesInput<Input = I> + HasExecutions + HasSolutions,
S::Solutions: Corpus<Input = I>,
I: Input,
{
/// Create a new in mem executor with the default timeout (5 sec)
pub fn generic<EM, OF, Z>(
@ -249,7 +242,7 @@ where
) -> Result<Self, Error>
where
EM: EventFirer<State = S> + EventRestarter,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, OT, S>,
OF: Feedback<EM, I, OT, S>,
Z: HasObjective<Objective = OF>,
{
Self::with_timeout_generic::<EM, OF, Z>(
@ -276,7 +269,7 @@ where
) -> Result<Self, Error>
where
EM: EventFirer<State = S> + EventRestarter,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, OT, S>,
OF: Feedback<EM, I, OT, S>,
Z: HasObjective<Objective = OF>,
{
let inner = GenericInProcessExecutorInner::batched_timeout_generic::<Self, EM, OF, Z>(
@ -309,7 +302,7 @@ where
) -> Result<Self, Error>
where
EM: EventFirer<State = S> + EventRestarter,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, OT, S>,
OF: Feedback<EM, I, OT, S>,
Z: HasObjective<Objective = OF>,
{
let inner = GenericInProcessExecutorInner::with_timeout_generic::<Self, EM, OF, Z>(
@ -337,62 +330,60 @@ where
/// The inprocess handlers
#[inline]
pub fn hooks(&self) -> &(InProcessHooks<S>, HT) {
pub fn hooks(&self) -> &(InProcessHooks<I, S>, HT) {
self.inner.hooks()
}
/// The inprocess handlers (mutable)
#[inline]
pub fn hooks_mut(&mut self) -> &mut (InProcessHooks<S>, HT) {
pub fn hooks_mut(&mut self) -> &mut (InProcessHooks<I, S>, HT) {
self.inner.hooks_mut()
}
}
/// The struct has [`InProcessHooks`].
pub trait HasInProcessHooks<S> {
pub trait HasInProcessHooks<I, S> {
/// Get the in-process handlers.
fn inprocess_hooks(&self) -> &InProcessHooks<S>;
fn inprocess_hooks(&self) -> &InProcessHooks<I, S>;
/// Get the mut in-process handlers.
fn inprocess_hooks_mut(&mut self) -> &mut InProcessHooks<S>;
fn inprocess_hooks_mut(&mut self) -> &mut InProcessHooks<I, S>;
}
impl<H, HB, HT, OT, S> HasInProcessHooks<S> for GenericInProcessExecutor<H, HB, HT, OT, S> {
impl<H, HB, HT, I, OT, S> HasInProcessHooks<I, S>
for GenericInProcessExecutor<H, HB, HT, I, OT, S>
{
/// the timeout handler
#[inline]
fn inprocess_hooks(&self) -> &InProcessHooks<S> {
fn inprocess_hooks(&self) -> &InProcessHooks<I, S> {
self.inner.inprocess_hooks()
}
/// the timeout handler
#[inline]
fn inprocess_hooks_mut(&mut self) -> &mut InProcessHooks<S> {
fn inprocess_hooks_mut(&mut self) -> &mut InProcessHooks<I, S> {
self.inner.inprocess_hooks_mut()
}
}
#[inline]
/// Save state if it is an objective
pub fn run_observers_and_save_state<E, EM, OF, S, Z>(
pub fn run_observers_and_save_state<E, EM, I, OF, S, Z>(
executor: &mut E,
state: &mut S,
input: &<S::Corpus as Corpus>::Input,
input: &I,
fuzzer: &mut Z,
event_mgr: &mut EM,
exitkind: ExitKind,
) where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
E: Executor<EM, I, S, Z> + HasObservers,
E::Observers: ObserversTuple<I, S>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
S: HasExecutions
+ HasSolutions
+ HasCorpus
+ HasCurrentTestcase
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase + UsesInput<Input = I>,
Z: HasObjective<Objective = OF>,
<S::Corpus as Corpus>::Input: Input + Clone,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
I: Input + Clone,
S::Solutions: Corpus<Input = I>,
{
let mut observers = executor.observers_mut();
@ -445,21 +436,16 @@ pub fn run_observers_and_save_state<E, EM, OF, S, Z>(
/// # Safety
/// This will directly access `GLOBAL_STATE` and related data pointers
#[cfg(any(unix, feature = "std"))]
pub unsafe fn generic_inproc_crash_handler<E, EM, OF, S, Z>()
pub unsafe fn generic_inproc_crash_handler<E, EM, I, OF, S, Z>()
where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
E: Executor<EM, I, S, Z> + HasObservers,
E::Observers: ObserversTuple<I, S>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
S: HasExecutions
+ HasSolutions
+ HasCorpus
+ HasCurrentTestcase
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
<S::Corpus as Corpus>::Input: Input + Clone,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
Z: HasObjective<Objective = OF>
+ ExecutionProcessor<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase + UsesInput<Input = I>,
I: Input + Clone,
S::Solutions: Corpus<Input = I>,
Z: HasObjective<Objective = OF> + ExecutionProcessor<EM, I, E::Observers, S>,
{
let data = &raw mut GLOBAL_STATE;
let in_handler = (*data).set_in_handler(true);
@ -469,9 +455,9 @@ where
let state = (*data).state_mut::<S>();
let event_mgr = (*data).event_mgr_mut::<EM>();
let fuzzer = (*data).fuzzer_mut::<Z>();
let input = (*data).take_current_input::<<S::Corpus as Corpus>::Input>();
let input = (*data).take_current_input::<I>();
run_observers_and_save_state::<E, EM, OF, S, Z>(
run_observers_and_save_state::<E, EM, I, OF, S, Z>(
executor,
state,
input,

View File

@ -28,15 +28,16 @@ use crate::{
/// The process executor simply calls a target function, as mutable reference to a closure
/// The internal state of the executor is made available to the harness.
pub type StatefulInProcessExecutor<'a, H, OT, S, ES> =
StatefulGenericInProcessExecutor<H, &'a mut H, (), OT, S, ES>;
pub type StatefulInProcessExecutor<'a, H, I, OT, S, ES> =
StatefulGenericInProcessExecutor<H, &'a mut H, (), I, 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(&mut ES, &<S as UsesInput>::Input) -> ExitKind,
Box<dyn FnMut(&mut ES, &<S as UsesInput>::Input) -> ExitKind>,
pub type OwnedInProcessExecutor<I, OT, S, ES> = StatefulGenericInProcessExecutor<
dyn FnMut(&mut ES, &I) -> ExitKind,
Box<dyn FnMut(&mut ES, &I) -> ExitKind>,
(),
I,
OT,
S,
ES,
@ -44,17 +45,17 @@ pub type OwnedInProcessExecutor<OT, S, ES> = StatefulGenericInProcessExecutor<
/// The inmem executor simply calls a target function, then returns afterwards.
/// The harness can access the internal state of the executor.
pub struct StatefulGenericInProcessExecutor<H, HB, HT, OT, S, ES> {
pub struct StatefulGenericInProcessExecutor<H, HB, HT, I, OT, S, ES> {
/// The harness function, being executed for each fuzzing loop execution
harness_fn: HB,
/// The state used as argument of the harness
pub exposed_executor_state: ES,
/// Inner state of the executor
pub inner: GenericInProcessExecutorInner<HT, OT, S>,
pub inner: GenericInProcessExecutorInner<HT, I, OT, S>,
phantom: PhantomData<(ES, *const H)>,
}
impl<H, HB, HT, OT, S, ES> Debug for StatefulGenericInProcessExecutor<H, HB, HT, OT, S, ES>
impl<H, HB, HT, I, OT, S, ES> Debug for StatefulGenericInProcessExecutor<H, HB, HT, I, OT, S, ES>
where
OT: Debug,
{
@ -66,13 +67,13 @@ where
}
}
impl<EM, H, HB, HT, OT, S, Z, ES> Executor<EM, <S::Corpus as Corpus>::Input, S, Z>
for StatefulGenericInProcessExecutor<H, HB, HT, OT, S, ES>
impl<EM, H, HB, HT, I, OT, S, Z, ES> Executor<EM, I, S, Z>
for StatefulGenericInProcessExecutor<H, HB, HT, I, OT, S, ES>
where
H: FnMut(&mut ES, &mut S, &<S::Corpus as Corpus>::Input) -> ExitKind + Sized,
H: FnMut(&mut ES, &mut S, &I) -> ExitKind + Sized,
HB: BorrowMut<H>,
HT: ExecutorHooksTuple<<S::Corpus as Corpus>::Input, S>,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
HT: ExecutorHooksTuple<I, S>,
OT: ObserversTuple<I, S>,
S: HasCorpus + HasExecutions,
{
fn run_target(
@ -80,7 +81,7 @@ where
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &<S::Corpus as Corpus>::Input,
input: &I,
) -> Result<ExitKind, Error> {
*state.executions_mut() += 1;
unsafe {
@ -98,12 +99,13 @@ where
}
}
impl<H, HB, HT, OT, S, ES> HasObservers for StatefulGenericInProcessExecutor<H, HB, HT, OT, S, ES>
impl<H, HB, HT, I, OT, S, ES> HasObservers
for StatefulGenericInProcessExecutor<H, HB, HT, I, OT, S, ES>
where
H: FnMut(&mut ES, &mut S, &<S::Corpus as Corpus>::Input) -> ExitKind + Sized,
H: FnMut(&mut ES, &mut S, &I) -> ExitKind + Sized,
HB: BorrowMut<H>,
HT: ExecutorHooksTuple<<S::Corpus as Corpus>::Input, S>,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
HT: ExecutorHooksTuple<I, S>,
OT: ObserversTuple<I, S>,
S: HasCorpus,
{
type Observers = OT;
@ -118,17 +120,13 @@ where
}
}
impl<'a, H, OT, S, ES> StatefulInProcessExecutor<'a, H, OT, S, ES>
impl<'a, H, I, OT, S, ES> StatefulInProcessExecutor<'a, H, I, OT, S, ES>
where
H: FnMut(&mut ES, &mut S, &<S::Corpus as Corpus>::Input) -> ExitKind + Sized,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
S: HasExecutions
+ HasSolutions
+ HasCorpus
+ HasCurrentTestcase
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
<S::Corpus as Corpus>::Input: Clone + Input,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
H: FnMut(&mut ES, &mut S, &I) -> ExitKind + Sized,
OT: ObserversTuple<I, S>,
S: HasExecutions + HasSolutions + HasCorpus + HasCurrentTestcase + UsesInput<Input = I>,
I: Clone + Input,
S::Solutions: Corpus<Input = I>,
{
/// Create a new in mem executor with the default timeout (5 sec)
pub fn new<EM, OF, Z>(
@ -141,7 +139,7 @@ where
) -> Result<Self, Error>
where
EM: EventFirer<State = S> + EventRestarter,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, OT, S>,
OF: Feedback<EM, I, OT, S>,
Z: HasObjective<Objective = OF>,
{
Self::with_timeout_generic(
@ -169,7 +167,7 @@ where
) -> Result<Self, Error>
where
EM: EventFirer<State = S> + EventRestarter,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, OT, S>,
OF: Feedback<EM, I, OT, S>,
Z: HasObjective<Objective = OF>,
{
let inner = GenericInProcessExecutorInner::batched_timeout_generic::<Self, EM, OF, Z>(
@ -208,7 +206,7 @@ where
) -> Result<Self, Error>
where
EM: EventFirer<State = S> + EventRestarter,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, OT, S>,
OF: Feedback<EM, I, OT, S>,
Z: HasObjective<Objective = OF>,
{
let inner = GenericInProcessExecutorInner::with_timeout_generic::<Self, EM, OF, Z>(
@ -229,7 +227,7 @@ where
}
}
impl<H, HB, HT, OT, S, ES> StatefulGenericInProcessExecutor<H, HB, HT, OT, S, ES> {
impl<H, HB, HT, I, OT, S, ES> StatefulGenericInProcessExecutor<H, HB, HT, I, OT, S, ES> {
/// The executor state given to the harness
pub fn exposed_executor_state(&self) -> &ES {
&self.exposed_executor_state
@ -241,20 +239,20 @@ impl<H, HB, HT, OT, S, ES> StatefulGenericInProcessExecutor<H, HB, HT, OT, S, ES
}
}
impl<H, HB, HT, OT, S, ES> StatefulGenericInProcessExecutor<H, HB, HT, OT, S, ES>
impl<H, HB, HT, I, OT, S, ES> StatefulGenericInProcessExecutor<H, HB, HT, I, OT, S, ES>
where
H: FnMut(&mut ES, &mut S, &<S::Corpus as Corpus>::Input) -> ExitKind + Sized,
H: FnMut(&mut ES, &mut S, &I) -> ExitKind + Sized,
HB: BorrowMut<H>,
HT: ExecutorHooksTuple<<S::Corpus as Corpus>::Input, S>,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
HT: ExecutorHooksTuple<I, S>,
I: Input + Clone,
OT: ObserversTuple<I, S>,
S: HasCorpus
+ HasExecutions
+ HasSolutions
+ HasCorpus
+ HasCurrentTestcase
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
<S::Corpus as Corpus>::Input: Input + Clone,
+ UsesInput<Input = I>,
S::Solutions: Corpus<Input = I>,
{
/// Create a new in mem executor with the default timeout (5 sec)
pub fn generic<EM, OF, Z>(
@ -268,7 +266,7 @@ where
) -> Result<Self, Error>
where
EM: EventFirer<State = S> + EventRestarter,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, OT, S>,
OF: Feedback<EM, I, OT, S>,
Z: HasObjective<Objective = OF>,
{
Self::with_timeout_generic(
@ -298,7 +296,7 @@ where
) -> Result<Self, Error>
where
EM: EventFirer<State = S> + EventRestarter,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, OT, S>,
OF: Feedback<EM, I, OT, S>,
Z: HasObjective<Objective = OF>,
{
let inner = GenericInProcessExecutorInner::batched_timeout_generic::<Self, EM, OF, Z>(
@ -334,7 +332,7 @@ where
) -> Result<Self, Error>
where
EM: EventFirer<State = S> + EventRestarter,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, OT, S>,
OF: Feedback<EM, I, OT, S>,
Z: HasObjective<Objective = OF>,
{
let inner = GenericInProcessExecutorInner::with_timeout_generic::<Self, EM, OF, Z>(
@ -363,29 +361,29 @@ where
/// The inprocess handlers
#[inline]
pub fn hooks(&self) -> &(InProcessHooks<S>, HT) {
pub fn hooks(&self) -> &(InProcessHooks<I, S>, HT) {
self.inner.hooks()
}
/// The inprocess handlers (mutable)
#[inline]
pub fn hooks_mut(&mut self) -> &mut (InProcessHooks<S>, HT) {
pub fn hooks_mut(&mut self) -> &mut (InProcessHooks<I, S>, HT) {
self.inner.hooks_mut()
}
}
impl<H, HB, HT, OT, S, ES> HasInProcessHooks<S>
for StatefulGenericInProcessExecutor<H, HB, HT, OT, S, ES>
impl<H, HB, HT, I, OT, S, ES> HasInProcessHooks<I, S>
for StatefulGenericInProcessExecutor<H, HB, HT, I, OT, S, ES>
{
/// the timeout handler
#[inline]
fn inprocess_hooks(&self) -> &InProcessHooks<S> {
fn inprocess_hooks(&self) -> &InProcessHooks<I, S> {
self.inner.inprocess_hooks()
}
/// the timeout handler
#[inline]
fn inprocess_hooks_mut(&mut self) -> &mut InProcessHooks<S> {
fn inprocess_hooks_mut(&mut self) -> &mut InProcessHooks<I, S> {
self.inner.inprocess_hooks_mut()
}
}

View File

@ -20,7 +20,6 @@ use nix::{
#[cfg(all(unix, not(target_os = "linux")))]
use crate::executors::hooks::timer::{setitimer, Itimerval, Timeval, ITIMER_REAL};
use crate::{
corpus::Corpus,
executors::{
hooks::{
inprocess_fork::{InChildProcessHooks, FORK_EXECUTOR_GLOBAL_DATA},
@ -34,18 +33,18 @@ use crate::{
};
/// Inner state of GenericInProcessExecutor-like structures.
pub struct GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z> {
pub(super) hooks: (InChildProcessHooks<S>, HT),
pub struct GenericInProcessForkExecutorInner<HT, I, OT, S, SP, EM, Z> {
pub(super) hooks: (InChildProcessHooks<I, S>, HT),
pub(super) shmem_provider: SP,
pub(super) observers: OT,
#[cfg(target_os = "linux")]
pub(super) itimerspec: libc::itimerspec,
#[cfg(all(unix, not(target_os = "linux")))]
pub(super) itimerval: Itimerval,
pub(super) phantom: PhantomData<(S, EM, Z)>,
pub(super) phantom: PhantomData<(I, S, EM, Z)>,
}
impl<HT, OT, S, SP, EM, Z> Debug for GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z>
impl<HT, I, OT, S, SP, EM, Z> Debug for GenericInProcessForkExecutorInner<HT, I, OT, S, SP, EM, Z>
where
HT: Debug,
OT: Debug,
@ -106,19 +105,19 @@ fn parse_itimerval(timeout: Duration) -> Itimerval {
}
}
impl<EM, HT, OT, S, SP, Z> GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z>
impl<EM, HT, I, OT, S, SP, Z> GenericInProcessForkExecutorInner<HT, I, OT, S, SP, EM, Z>
where
HT: ExecutorHooksTuple<<S::Corpus as Corpus>::Input, S>,
HT: ExecutorHooksTuple<I, S>,
S: HasCorpus,
SP: ShMemProvider,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
OT: ObserversTuple<I, S>,
{
pub(super) unsafe fn pre_run_target_child(
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &<S::Corpus as Corpus>::Input,
input: &I,
) -> Result<(), Error> {
self.shmem_provider.post_fork(true)?;
@ -153,7 +152,7 @@ where
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &<S::Corpus as Corpus>::Input,
input: &I,
) {
self.observers
.post_exec_child_all(state, input, &ExitKind::Ok)
@ -198,21 +197,15 @@ where
}
}
impl<HT, OT, S, SP, EM, Z> GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z>
impl<HT, I, OT, S, SP, EM, Z> GenericInProcessForkExecutorInner<HT, I, OT, S, SP, EM, Z>
where
HT: ExecutorHooksTuple<<S::Corpus as Corpus>::Input, S>,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
HT: ExecutorHooksTuple<I, S>,
OT: ObserversTuple<I, S>,
S: HasCorpus,
{
#[inline]
/// This function marks the boundary between the fuzzer and the target.
pub fn enter_target(
&mut self,
_fuzzer: &mut Z,
state: &mut S,
_event_mgr: &mut EM,
input: &<S::Corpus as Corpus>::Input,
) {
pub fn enter_target(&mut self, _fuzzer: &mut Z, state: &mut S, _event_mgr: &mut EM, input: &I) {
unsafe {
let data = &raw mut FORK_EXECUTOR_GLOBAL_DATA;
write_volatile(
@ -238,7 +231,7 @@ where
_fuzzer: &mut Z,
_state: &mut S,
_event_mgr: &mut EM,
_input: &<S::Corpus as Corpus>::Input,
_input: &I,
) {
// do nothing
}
@ -294,8 +287,8 @@ where
}
}
impl<HT, OT, S, SP, EM, Z> HasObservers
for GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z>
impl<HT, I, OT, S, SP, EM, Z> HasObservers
for GenericInProcessForkExecutorInner<HT, I, OT, S, SP, EM, Z>
{
type Observers = OT;

View File

@ -14,7 +14,6 @@ use nix::unistd::{fork, ForkResult};
use super::hooks::ExecutorHooksTuple;
use crate::{
corpus::Corpus,
executors::{
hooks::inprocess_fork::InProcessForkExecutorGlobalData,
inprocess_fork::inner::GenericInProcessForkExecutorInner, Executor, ExitKind, HasObservers,
@ -40,12 +39,12 @@ pub mod stateful;
///
/// On Linux, when fuzzing a Rust target, set `panic = "abort"` in your `Cargo.toml` (see [Cargo documentation](https://doc.rust-lang.org/cargo/reference/profiles.html#panic)).
/// Else panics can not be caught by `LibAFL`.
pub type InProcessForkExecutor<'a, H, OT, S, SP, EM, Z> =
GenericInProcessForkExecutor<'a, H, (), OT, S, SP, EM, Z>;
pub type InProcessForkExecutor<'a, H, I, OT, S, SP, EM, Z> =
GenericInProcessForkExecutor<'a, H, (), I, OT, S, SP, EM, Z>;
impl<'a, H, OT, S, SP, EM, Z> InProcessForkExecutor<'a, H, OT, S, SP, EM, Z>
impl<'a, H, I, OT, S, SP, EM, Z> InProcessForkExecutor<'a, H, I, OT, S, SP, EM, Z>
where
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
OT: ObserversTuple<I, S>,
S: HasCorpus,
{
/// The constructor for `InProcessForkExecutor`
@ -75,12 +74,13 @@ where
///
/// On Linux, when fuzzing a Rust target, set `panic = "abort"` in your `Cargo.toml` (see [Cargo documentation](https://doc.rust-lang.org/cargo/reference/profiles.html#panic)).
/// Else panics can not be caught by `LibAFL`.
pub struct GenericInProcessForkExecutor<'a, H, HT, OT, S, SP, EM, Z> {
pub struct GenericInProcessForkExecutor<'a, H, HT, I, OT, S, SP, EM, Z> {
harness_fn: &'a mut H,
inner: GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z>,
inner: GenericInProcessForkExecutorInner<HT, I, OT, S, SP, EM, Z>,
}
impl<H, HT, OT, S, SP, EM, Z> Debug for GenericInProcessForkExecutor<'_, H, HT, OT, S, SP, EM, Z>
impl<H, HT, I, OT, S, SP, EM, Z> Debug
for GenericInProcessForkExecutor<'_, H, HT, I, OT, S, SP, EM, Z>
where
HT: Debug,
OT: Debug,
@ -103,14 +103,14 @@ where
}
}
impl<EM, H, HT, OT, S, SP, Z> Executor<EM, <S::Corpus as Corpus>::Input, S, Z>
for GenericInProcessForkExecutor<'_, H, HT, OT, S, SP, EM, Z>
impl<EM, H, HT, I, OT, S, SP, Z> Executor<EM, I, S, Z>
for GenericInProcessForkExecutor<'_, H, HT, I, OT, S, SP, EM, Z>
where
H: FnMut(&<S::Corpus as Corpus>::Input) -> ExitKind + Sized,
H: FnMut(&I) -> ExitKind + Sized,
S: HasCorpus + HasExecutions,
SP: ShMemProvider,
HT: ExecutorHooksTuple<<S::Corpus as Corpus>::Input, S>,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
HT: ExecutorHooksTuple<I, S>,
OT: ObserversTuple<I, S>,
{
#[inline]
fn run_target(
@ -118,7 +118,7 @@ where
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &<S::Corpus as Corpus>::Input,
input: &I,
) -> Result<ExitKind, Error> {
*state.executions_mut() += 1;
@ -142,10 +142,10 @@ where
}
}
impl<'a, H, HT, OT, S, SP, EM, Z> GenericInProcessForkExecutor<'a, H, HT, OT, S, SP, EM, Z>
impl<'a, H, HT, I, OT, S, SP, EM, Z> GenericInProcessForkExecutor<'a, H, HT, I, OT, S, SP, EM, Z>
where
HT: ExecutorHooksTuple<<S::Corpus as Corpus>::Input, S>,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
HT: ExecutorHooksTuple<I, S>,
OT: ObserversTuple<I, S>,
S: HasCorpus,
{
/// Creates a new [`GenericInProcessForkExecutor`] with custom hooks
@ -188,8 +188,8 @@ where {
}
}
impl<H, HT, OT, S, SP, EM, Z> HasObservers
for GenericInProcessForkExecutor<'_, H, HT, OT, S, SP, EM, Z>
impl<H, HT, I, OT, S, SP, EM, Z> HasObservers
for GenericInProcessForkExecutor<'_, H, HT, I, OT, S, SP, EM, Z>
{
type Observers = OT;
#[inline]
@ -356,7 +356,7 @@ mod tests {
};
let mut harness = |_buf: &NopInput| ExitKind::Ok;
let default = InChildProcessHooks::nop();
let default = InChildProcessHooks::<NopInput, NopState<NopInput>>::nop();
#[cfg(target_os = "linux")]
let mut in_process_fork_executor = GenericInProcessForkExecutor {
harness_fn: &mut harness,

View File

@ -15,7 +15,6 @@ use libafl_bolts::{
use nix::unistd::{fork, ForkResult};
use crate::{
corpus::Corpus,
executors::{
hooks::ExecutorHooksTuple, inprocess_fork::GenericInProcessForkExecutorInner, Executor,
ExitKind, HasObservers,
@ -26,12 +25,12 @@ use crate::{
};
/// The `StatefulInProcessForkExecutor` with no user hooks
pub type StatefulInProcessForkExecutor<'a, H, OT, S, SP, ES, EM, Z> =
StatefulGenericInProcessForkExecutor<'a, H, (), OT, S, SP, ES, EM, Z>;
pub type StatefulInProcessForkExecutor<'a, H, I, OT, S, SP, ES, EM, Z> =
StatefulGenericInProcessForkExecutor<'a, H, (), I, OT, S, SP, ES, EM, Z>;
impl<'a, H, OT, S, SP, ES, EM, Z> StatefulInProcessForkExecutor<'a, H, OT, S, SP, ES, EM, Z>
impl<'a, H, I, OT, S, SP, ES, EM, Z> StatefulInProcessForkExecutor<'a, H, I, OT, S, SP, ES, EM, Z>
where
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
OT: ObserversTuple<I, S>,
S: HasCorpus,
{
#[expect(clippy::too_many_arguments)]
@ -61,18 +60,18 @@ where
}
/// [`StatefulGenericInProcessForkExecutor`] is an executor that forks the current process before each execution. Harness can access some internal state.
pub struct StatefulGenericInProcessForkExecutor<'a, H, HT, OT, S, SP, ES, EM, Z> {
pub struct StatefulGenericInProcessForkExecutor<'a, H, HT, I, OT, S, SP, ES, EM, Z> {
/// The harness function, being executed for each fuzzing loop execution
harness_fn: &'a mut H,
/// The state used as argument of the harness
pub exposed_executor_state: ES,
/// Inner state of the executor
pub inner: GenericInProcessForkExecutorInner<HT, OT, S, SP, EM, Z>,
pub inner: GenericInProcessForkExecutorInner<HT, I, OT, S, SP, EM, Z>,
phantom: PhantomData<ES>,
}
impl<H, HT, OT, S, SP, ES, EM, Z> Debug
for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z>
impl<H, HT, I, OT, S, SP, ES, EM, Z> Debug
for StatefulGenericInProcessForkExecutor<'_, H, HT, I, OT, S, SP, ES, EM, Z>
where
HT: Debug,
OT: Debug,
@ -95,14 +94,14 @@ where
}
}
impl<EM, H, HT, OT, S, SP, Z, ES> Executor<EM, <S::Corpus as Corpus>::Input, S, Z>
for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z>
impl<EM, H, HT, I, OT, S, SP, Z, ES> Executor<EM, I, S, Z>
for StatefulGenericInProcessForkExecutor<'_, H, HT, I, OT, S, SP, ES, EM, Z>
where
H: FnMut(&mut ES, &<S::Corpus as Corpus>::Input) -> ExitKind + Sized,
HT: ExecutorHooksTuple<<<S as HasCorpus>::Corpus as Corpus>::Input, S>,
H: FnMut(&mut ES, &I) -> ExitKind + Sized,
HT: ExecutorHooksTuple<I, S>,
S: HasCorpus + HasExecutions,
SP: ShMemProvider,
OT: ObserversTuple<<<S as HasCorpus>::Corpus as Corpus>::Input, S>,
OT: ObserversTuple<I, S>,
{
#[inline]
fn run_target(
@ -110,7 +109,7 @@ where
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &<S::Corpus as Corpus>::Input,
input: &I,
) -> Result<ExitKind, Error> {
*state.executions_mut() += 1;
@ -134,11 +133,11 @@ where
}
}
impl<'a, H, HT, OT, S, SP, ES, EM, Z>
StatefulGenericInProcessForkExecutor<'a, H, HT, OT, S, SP, ES, EM, Z>
impl<'a, H, HT, I, OT, S, SP, ES, EM, Z>
StatefulGenericInProcessForkExecutor<'a, H, HT, I, OT, S, SP, ES, EM, Z>
where
HT: ExecutorHooksTuple<<S::Corpus as Corpus>::Input, S>,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
HT: ExecutorHooksTuple<I, S>,
OT: ObserversTuple<I, S>,
S: HasCorpus,
{
/// Creates a new [`StatefulGenericInProcessForkExecutor`] with custom hooks
@ -183,8 +182,8 @@ where
}
}
impl<H, HT, OT, S, SP, ES, EM, Z> HasObservers
for StatefulGenericInProcessForkExecutor<'_, H, HT, OT, S, SP, ES, EM, Z>
impl<H, HT, I, OT, S, SP, ES, EM, Z> HasObservers
for StatefulGenericInProcessForkExecutor<'_, H, HT, I, OT, S, SP, ES, EM, Z>
{
type Observers = OT;

View File

@ -7,20 +7,20 @@ use frida_gum::{
stalker::{NoneEventSink, Stalker},
Gum, MemoryRange, NativePointer,
};
#[cfg(windows)]
use libafl::{
corpus::Corpus,
executors::{hooks::inprocess::InProcessHooks, inprocess::HasInProcessHooks},
inputs::Input,
state::{HasCurrentTestcase, HasSolutions},
};
use libafl::{
executors::{Executor, ExitKind, HasObservers, InProcessExecutor},
inputs::{NopTargetBytesConverter, TargetBytesConverter, UsesInput},
observers::ObserversTuple,
state::{HasCorpus, HasExecutions, UsesState},
Error,
};
#[cfg(windows)]
use libafl::{
executors::{hooks::inprocess::InProcessHooks, inprocess::HasInProcessHooks},
inputs::Input,
state::{HasCurrentTestcase, HasSolutions},
};
use libafl_bolts::{tuples::RefIndexable, AsSlice};
#[cfg(not(test))]
@ -30,8 +30,8 @@ use crate::helper::{FridaInstrumentationHelper, FridaRuntimeTuple};
use crate::windows_hooks::initialize;
/// The [`FridaInProcessExecutor`] is an [`Executor`] that executes the target in the same process, usinig [`frida`](https://frida.re/) for binary-only instrumentation.
pub struct FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S, TC> {
base: InProcessExecutor<'a, H, OT, S>,
pub struct FridaInProcessExecutor<'a, 'b, 'c, H, I, OT, RT, S, TC> {
base: InProcessExecutor<'a, H, I, OT, S>,
/// `thread_id` for the Stalker
thread_id: Option<u32>,
/// Frida's dynamic rewriting engine
@ -43,7 +43,7 @@ pub struct FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S, TC> {
_phantom: PhantomData<&'b u8>,
}
impl<H, OT, RT, S, TC> Debug for FridaInProcessExecutor<'_, '_, '_, H, OT, RT, S, TC>
impl<H, I, OT, RT, S, TC> Debug for FridaInProcessExecutor<'_, '_, '_, H, I, OT, RT, S, TC>
where
OT: Debug,
{
@ -56,14 +56,14 @@ where
}
}
impl<EM, H, OT, RT, S, TC, Z> Executor<EM, <S::Corpus as Corpus>::Input, S, Z>
for FridaInProcessExecutor<'_, '_, '_, H, OT, RT, S, TC>
impl<EM, H, I, OT, RT, S, TC, Z> Executor<EM, I, S, Z>
for FridaInProcessExecutor<'_, '_, '_, H, I, OT, RT, S, TC>
where
EM: UsesState<State = S>,
H: FnMut(&<S::Corpus as Corpus>::Input) -> ExitKind,
S: HasCorpus + HasExecutions + UsesInput<Input = <S::Corpus as Corpus>::Input>,
TC: TargetBytesConverter<Input = <S::Corpus as Corpus>::Input>,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
H: FnMut(&I) -> ExitKind,
S: HasCorpus + HasExecutions + UsesInput<Input = I>,
TC: TargetBytesConverter<Input = I>,
OT: ObserversTuple<I, S>,
RT: FridaRuntimeTuple,
{
/// Instruct the target about the input and run
@ -73,7 +73,7 @@ where
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &<S::Corpus as Corpus>::Input,
input: &I,
) -> Result<ExitKind, Error> {
let target_bytes = self.target_bytes_converter.to_target_bytes(input);
self.helper.pre_exec(target_bytes.as_slice())?;
@ -113,7 +113,7 @@ where
}
}
impl<H, OT, RT, S, TC> HasObservers for FridaInProcessExecutor<'_, '_, '_, H, OT, RT, S, TC> {
impl<H, I, OT, RT, S, TC> HasObservers for FridaInProcessExecutor<'_, '_, '_, H, I, OT, RT, S, TC> {
type Observers = OT;
#[inline]
fn observers(&self) -> RefIndexable<&Self::Observers, Self::Observers> {
@ -126,17 +126,8 @@ impl<H, OT, RT, S, TC> HasObservers for FridaInProcessExecutor<'_, '_, '_, H, OT
}
}
impl<'a, 'b, 'c, H, OT, RT, S>
FridaInProcessExecutor<
'a,
'b,
'c,
H,
OT,
RT,
S,
NopTargetBytesConverter<<S::Corpus as Corpus>::Input>,
>
impl<'a, 'b, 'c, H, I, OT, RT, S>
FridaInProcessExecutor<'a, 'b, 'c, H, I, OT, RT, S, NopTargetBytesConverter<I>>
where
S: HasCorpus,
RT: FridaRuntimeTuple,
@ -144,7 +135,7 @@ where
/// Creates a new [`FridaInProcessExecutor`].
pub fn new(
gum: &'a Gum,
base: InProcessExecutor<'a, H, OT, S>,
base: InProcessExecutor<'a, H, I, OT, S>,
helper: &'c mut FridaInstrumentationHelper<'b, RT>,
) -> Self {
FridaInProcessExecutor::with_target_bytes_converter(
@ -159,7 +150,7 @@ where
/// Creates a new [`FridaInProcessExecutor`] tracking the given `thread_id`.
pub fn on_thread(
gum: &'a Gum,
base: InProcessExecutor<'a, H, OT, S>,
base: InProcessExecutor<'a, H, I, OT, S>,
helper: &'c mut FridaInstrumentationHelper<'b, RT>,
thread_id: u32,
) -> Self {
@ -173,14 +164,14 @@ where
}
}
impl<'a, 'b, 'c, H, OT, RT, S, TC> FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S, TC>
impl<'a, 'b, 'c, H, I, OT, RT, S, TC> FridaInProcessExecutor<'a, 'b, 'c, H, I, OT, RT, S, TC>
where
RT: FridaRuntimeTuple,
{
/// Creates a new [`FridaInProcessExecutor`].
pub fn with_target_bytes_converter(
gum: &'a Gum,
base: InProcessExecutor<'a, H, OT, S>,
base: InProcessExecutor<'a, H, I, OT, S>,
helper: &'c mut FridaInstrumentationHelper<'b, RT>,
thread_id: Option<u32>,
target_bytes_converter: TC,
@ -231,30 +222,26 @@ where
}
#[cfg(windows)]
impl<'a, 'b, 'c, H, OT, RT, S, TC> HasInProcessHooks<S>
for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S, TC>
impl<'a, 'b, 'c, H, I, OT, RT, S, TC> HasInProcessHooks<I, S>
for FridaInProcessExecutor<'a, 'b, 'c, H, I, OT, RT, S, TC>
where
H: FnMut(&<S::Corpus as Corpus>::Input) -> ExitKind,
S: HasSolutions
+ HasCorpus
+ HasCurrentTestcase
+ HasExecutions
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
<S::Corpus as Corpus>::Input: Input,
TC: TargetBytesConverter<Input = <S::Corpus as Corpus>::Input>,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
H: FnMut(&I) -> ExitKind,
S: HasSolutions + HasCorpus + HasCurrentTestcase + HasExecutions + UsesInput<Input = I>,
S::Solutions: Corpus<Input = I>,
I: Input,
TC: TargetBytesConverter<Input = I>,
OT: ObserversTuple<I, S>,
RT: FridaRuntimeTuple,
{
/// the timeout handler
#[inline]
fn inprocess_hooks(&self) -> &InProcessHooks<S> {
fn inprocess_hooks(&self) -> &InProcessHooks<I, S> {
&self.base.hooks().0
}
/// the timeout handler
#[inline]
fn inprocess_hooks_mut(&mut self) -> &mut InProcessHooks<S> {
fn inprocess_hooks_mut(&mut self) -> &mut InProcessHooks<I, S> {
&mut self.base.hooks_mut().0
}
}

View File

@ -8,49 +8,25 @@ use std::{
},
};
use libafl::inputs::UsesInput;
use libafl_qemu_sys::GuestAddr;
use crate::{command::CommandManager, Qemu};
use crate::Qemu;
#[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct BreakpointId(u64);
// TODO: distinguish breakpoints with IDs instead of addresses to avoid collisions.
pub struct Breakpoint<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
#[derive(Clone)]
pub struct Breakpoint<C> {
id: BreakpointId,
addr: GuestAddr,
cmd: Option<CM::Commands>,
cmd: Option<C>,
disable_on_trigger: bool,
enabled: bool,
}
impl<CM, ED, ET, S, SM> Clone for Breakpoint<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
fn clone(&self) -> Self {
Self {
id: self.id,
addr: self.addr,
cmd: self.cmd.clone(),
disable_on_trigger: self.disable_on_trigger,
enabled: self.enabled,
}
}
}
impl<CM, ED, ET, S, SM> Debug for Breakpoint<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
impl<C> Debug for Breakpoint<C> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "BP {:?} @ addr {:?}", self.id, self.addr)
}
@ -71,68 +47,39 @@ impl Default for BreakpointId {
}
}
impl<CM, ED, ET, S, SM> Hash for Breakpoint<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
impl<C> Hash for Breakpoint<C> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
impl<CM, ED, ET, S, SM> PartialEq for Breakpoint<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
impl<C> PartialEq for Breakpoint<C> {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl<CM, ED, ET, S, SM> Eq for Breakpoint<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
}
impl<C> Eq for Breakpoint<C> {}
impl<CM, ED, ET, S, SM> Display for Breakpoint<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
impl<C> Display for Breakpoint<C> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Breakpoint @vaddr 0x{:x}", self.addr)
}
}
impl<CM, ED, ET, S, SM> Borrow<BreakpointId> for Breakpoint<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
impl<C> Borrow<BreakpointId> for Breakpoint<C> {
fn borrow(&self) -> &BreakpointId {
&self.id
}
}
impl<CM, ED, ET, S, SM> Borrow<GuestAddr> for Breakpoint<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
impl<C> Borrow<GuestAddr> for Breakpoint<C> {
fn borrow(&self) -> &GuestAddr {
&self.addr
}
}
impl<CM, ED, ET, S, SM> Breakpoint<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
impl<C> Breakpoint<C> {
// Emu will return with the breakpoint as exit reason.
#[must_use]
pub fn without_command(addr: GuestAddr, disable_on_trigger: bool) -> Self {
@ -147,7 +94,7 @@ where
// Emu will execute the command when it meets the breakpoint.
#[must_use]
pub fn with_command(addr: GuestAddr, cmd: CM::Commands, disable_on_trigger: bool) -> Self {
pub fn with_command(addr: GuestAddr, cmd: C, disable_on_trigger: bool) -> Self {
Self {
id: BreakpointId::new(),
addr,
@ -181,7 +128,10 @@ where
}
}
pub fn trigger(&mut self, qemu: Qemu) -> Option<CM::Commands> {
pub fn trigger(&mut self, qemu: Qemu) -> Option<C>
where
C: Clone,
{
if self.disable_on_trigger {
self.disable(qemu);
}

View File

@ -6,10 +6,7 @@ use std::{
};
use enum_map::{Enum, EnumMap};
use libafl::{
executors::ExitKind,
inputs::{HasTargetBytes, UsesInput},
};
use libafl::{executors::ExitKind, inputs::HasTargetBytes};
use libafl_bolts::AsSlice;
use libafl_qemu_sys::GuestAddr;
#[cfg(feature = "systemmode")]
@ -99,11 +96,11 @@ macro_rules! define_std_command_manager {
}
}
impl<ET, S, SM> CommandManager<StdEmulatorDriver, ET, S, SM> for $name<S>
impl<C, ET, I, S, SM> CommandManager<C, StdEmulatorDriver, ET, I, S, SM> for $name<S>
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
type Commands = [<$name Commands>];
@ -115,7 +112,7 @@ macro_rules! define_std_command_manager {
match cmd_id {
// <StartPhysCommandParser as NativeCommandParser<S>>::COMMAND_ID => Ok(StdCommandManagerCommands::StartPhysCommandParserCmd(<StartPhysCommandParser as NativeCommandParser<S>>::parse(qemu, arch_regs_map)?)),
$(<$native_command_parser as NativeCommandParser<Self, StdEmulatorDriver, ET, S, SM>>::COMMAND_ID => Ok(<$native_command_parser as NativeCommandParser<Self, StdEmulatorDriver, ET, S, SM>>::parse(qemu, arch_regs_map)?.into())),+,
$(<$native_command_parser as NativeCommandParser<C, Self, StdEmulatorDriver, ET, I, S, SM>>::COMMAND_ID => Ok(<$native_command_parser as NativeCommandParser<C, Self, StdEmulatorDriver, ET, I, S, SM>>::parse(qemu, arch_regs_map)?.into())),+,
_ => Err(CommandError::UnknownCommand(cmd_id.into())),
}
}
@ -128,25 +125,25 @@ macro_rules! define_std_command_manager {
$($command($command)),+,
}
impl<ET, S, SM> IsCommand<$name<S>, StdEmulatorDriver, ET, S, SM> for [<$name Commands>]
impl<C, ET, I, S, SM> IsCommand<C, $name<S>, StdEmulatorDriver, ET, I, S, SM> for [<$name Commands>]
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
fn usable_at_runtime(&self) -> bool {
match self {
$([<$name Commands>]::$command(cmd) => <$command as IsCommand<$name<S>, StdEmulatorDriver, ET, S, SM>>::usable_at_runtime(cmd)),+
$([<$name Commands>]::$command(cmd) => <$command as IsCommand<C, $name<S>, StdEmulatorDriver, ET, I, S, SM>>::usable_at_runtime(cmd)),+
}
}
fn run(&self,
emu: &mut Emulator<$name<S>, StdEmulatorDriver, ET, S, SM>,
emu: &mut Emulator<C, $name<S>, StdEmulatorDriver, ET, I, S, SM>,
state: &mut S,
input: &S::Input,
input: &I,
ret_reg: Option<Regs>
) -> Result<Option<EmulatorDriverResult<$name<S>, StdEmulatorDriver, ET, S, SM>>, EmulatorDriverError> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
match self {
$([<$name Commands>]::$command(cmd) => cmd.run(emu, state, input, ret_reg)),+
}
@ -164,21 +161,15 @@ macro_rules! define_std_command_manager {
};
}
pub trait CommandManager<ED, ET, S, SM>: Sized + Debug
where
S: UsesInput,
{
type Commands: IsCommand<Self, ED, ET, S, SM>;
pub trait CommandManager<C, ED, ET, I, S, SM>: Sized + Debug {
type Commands: IsCommand<C, Self, ED, ET, I, S, SM>;
fn parse(&self, qemu: Qemu) -> Result<Self::Commands, CommandError>;
}
#[derive(Clone, Debug)]
pub struct NopCommandManager;
impl<ED, ET, S, SM> CommandManager<ED, ET, S, SM> for NopCommandManager
where
S: UsesInput,
{
impl<C, ED, ET, I, S, SM> CommandManager<C, ED, ET, I, S, SM> for NopCommandManager {
type Commands = NopCommand;
fn parse(&self, _qemu: Qemu) -> Result<Self::Commands, CommandError> {
@ -222,13 +213,10 @@ pub enum NativeExitKind {
Crash = bindings::LibaflQemuEndStatus_LIBAFL_QEMU_END_CRASH.0 as u64, // Crash reported in the VM
}
pub trait IsCommand<CM, ED, ET, S, SM>: Clone + Debug
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
pub trait IsCommand<C, CM, ED, ET, I, S, SM>: Clone + Debug {
/// Used to know whether the command can be run during a backdoor, or if it is necessary to go out of
/// the QEMU VM to run the command.
// TODO: Use const when stabilized
fn usable_at_runtime(&self) -> bool;
/// Command handler.
@ -236,14 +224,13 @@ where
/// - `ret_reg`: The register in which the guest return value should be written, if any.
/// Returns
/// - `InnerHandlerResult`: How the high-level handler should behave
#[expect(clippy::type_complexity)]
fn run(
&self,
emu: &mut Emulator<CM, ED, ET, S, SM>,
emu: &mut Emulator<C, CM, ED, ET, I, S, SM>,
state: &mut S,
input: &S::Input,
input: &I,
ret_reg: Option<Regs>,
) -> Result<Option<EmulatorDriverResult<CM, ED, ET, S, SM>>, EmulatorDriverError>;
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError>;
}
#[derive(Debug, Clone)]
@ -272,33 +259,29 @@ impl Display for NopCommand {
}
}
impl<CM, ED, ET, S, SM> IsCommand<CM, ED, ET, S, SM> for NopCommand
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
impl<C, CM, ED, ET, I, S, SM> IsCommand<C, CM, ED, ET, I, S, SM> for NopCommand {
fn usable_at_runtime(&self) -> bool {
true
}
fn run(
&self,
_emu: &mut Emulator<CM, ED, ET, S, SM>,
_emu: &mut Emulator<C, CM, ED, ET, I, S, SM>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_ret_reg: Option<Regs>,
) -> Result<Option<EmulatorDriverResult<CM, ED, ET, S, SM>>, EmulatorDriverError> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
Ok(None)
}
}
#[derive(Debug, Clone)]
pub struct SaveCommand;
impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorDriver, ET, S, SM> for SaveCommand
impl<C, CM, ET, I, S, SM> IsCommand<C, CM, StdEmulatorDriver, ET, I, S, SM> for SaveCommand
where
ET: EmulatorModuleTuple<S>,
CM: CommandManager<StdEmulatorDriver, ET, S, SM>,
S: UsesInput + Unpin,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
fn usable_at_runtime(&self) -> bool {
@ -307,12 +290,11 @@ where
fn run(
&self,
emu: &mut Emulator<CM, StdEmulatorDriver, ET, S, SM>,
emu: &mut Emulator<C, CM, StdEmulatorDriver, ET, I, S, SM>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_ret_reg: Option<Regs>,
) -> Result<Option<EmulatorDriverResult<CM, StdEmulatorDriver, ET, S, SM>>, EmulatorDriverError>
{
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
let qemu = emu.qemu();
let snapshot_id = emu.snapshot_manager_mut().save(qemu);
@ -327,10 +309,10 @@ where
#[derive(Debug, Clone)]
pub struct LoadCommand;
impl<CM, ET, S, SM> IsCommand<CM, StdEmulatorDriver, ET, S, SM> for LoadCommand
impl<C, CM, ET, I, S, SM> IsCommand<C, CM, StdEmulatorDriver, ET, I, S, SM> for LoadCommand
where
CM: CommandManager<StdEmulatorDriver, ET, S, SM>,
S: UsesInput,
// CM: CommandManager<C, StdEmulatorDriver, ET, I, S, SM>,
// ET: EmulatorModuleTuple<I, S>,
SM: IsSnapshotManager,
{
fn usable_at_runtime(&self) -> bool {
@ -339,12 +321,11 @@ where
fn run(
&self,
emu: &mut Emulator<CM, StdEmulatorDriver, ET, S, SM>,
emu: &mut Emulator<C, CM, StdEmulatorDriver, ET, I, S, SM>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_ret_reg: Option<Regs>,
) -> Result<Option<EmulatorDriverResult<CM, StdEmulatorDriver, ET, S, SM>>, EmulatorDriverError>
{
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
let qemu = emu.qemu();
let snapshot_id = emu
@ -367,11 +348,9 @@ pub struct InputCommand {
cpu: CPU,
}
impl<CM, ED, ET, S, SM> IsCommand<CM, ED, ET, S, SM> for InputCommand
impl<C, CM, ED, ET, I, S, SM> IsCommand<C, CM, ED, ET, I, S, SM> for InputCommand
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
S::Input: HasTargetBytes,
I: HasTargetBytes,
{
fn usable_at_runtime(&self) -> bool {
true
@ -379,11 +358,11 @@ where
fn run(
&self,
emu: &mut Emulator<CM, ED, ET, S, SM>,
emu: &mut Emulator<C, CM, ED, ET, I, S, SM>,
_state: &mut S,
input: &S::Input,
input: &I,
ret_reg: Option<Regs>,
) -> Result<Option<EmulatorDriverResult<CM, ED, ET, S, SM>>, EmulatorDriverError> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
let qemu = emu.qemu();
let ret_value = self
@ -403,11 +382,12 @@ where
pub struct StartCommand {
input_location: QemuMemoryChunk,
}
impl<ET, S, SM> IsCommand<StdCommandManager<S>, StdEmulatorDriver, ET, S, SM> for StartCommand
impl<C, ET, I, S, SM> IsCommand<C, StdCommandManager<S>, StdEmulatorDriver, ET, I, S, SM>
for StartCommand
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
fn usable_at_runtime(&self) -> bool {
@ -416,14 +396,11 @@ where
fn run(
&self,
emu: &mut Emulator<StdCommandManager<S>, StdEmulatorDriver, ET, S, SM>,
emu: &mut Emulator<C, StdCommandManager<S>, StdEmulatorDriver, ET, I, S, SM>,
state: &mut S,
input: &S::Input,
input: &I,
ret_reg: Option<Regs>,
) -> Result<
Option<EmulatorDriverResult<StdCommandManager<S>, StdEmulatorDriver, ET, S, SM>>,
EmulatorDriverError,
> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
if emu.command_manager_mut().start() {
return Err(EmulatorDriverError::CommandError(
CommandError::StartedTwice,
@ -490,11 +467,12 @@ pub struct EndCommand {
exit_kind: Option<ExitKind>,
}
impl<ET, S, SM> IsCommand<StdCommandManager<S>, StdEmulatorDriver, ET, S, SM> for EndCommand
impl<C, ET, I, S, SM> IsCommand<C, StdCommandManager<S>, StdEmulatorDriver, ET, I, S, SM>
for EndCommand
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
fn usable_at_runtime(&self) -> bool {
@ -503,14 +481,11 @@ where
fn run(
&self,
emu: &mut Emulator<StdCommandManager<S>, StdEmulatorDriver, ET, S, SM>,
emu: &mut Emulator<C, StdCommandManager<S>, StdEmulatorDriver, ET, I, S, SM>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_ret_reg: Option<Regs>,
) -> Result<
Option<EmulatorDriverResult<StdCommandManager<S>, StdEmulatorDriver, ET, S, SM>>,
EmulatorDriverError,
> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
let qemu = emu.qemu();
if !emu.command_manager_mut().has_started() {
@ -538,22 +513,18 @@ where
#[derive(Debug, Clone)]
pub struct VersionCommand(u64);
impl<CM, ED, ET, S, SM> IsCommand<CM, ED, ET, S, SM> for VersionCommand
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
impl<C, CM, ED, ET, I, S, SM> IsCommand<C, CM, ED, ET, I, S, SM> for VersionCommand {
fn usable_at_runtime(&self) -> bool {
true
}
fn run(
&self,
_emu: &mut Emulator<CM, ED, ET, S, SM>,
_emu: &mut Emulator<C, CM, ED, ET, I, S, SM>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_ret_reg: Option<Regs>,
) -> Result<Option<EmulatorDriverResult<CM, ED, ET, S, SM>>, EmulatorDriverError> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
let guest_version = self.0;
if VERSION == guest_version {
@ -573,11 +544,11 @@ pub struct PageAllowCommand {
}
#[cfg(feature = "systemmode")]
impl<CM, ED, ET, S, SM> IsCommand<CM, ED, ET, S, SM> for PageAllowCommand
impl<C, CM, ED, ET, I, S, SM> IsCommand<C, CM, ED, ET, I, S, SM> for PageAllowCommand
where
ET: EmulatorModuleTuple<S>,
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput + Unpin,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
fn usable_at_runtime(&self) -> bool {
true
@ -585,11 +556,11 @@ where
fn run(
&self,
emu: &mut Emulator<CM, ED, ET, S, SM>,
emu: &mut Emulator<C, CM, ED, ET, I, S, SM>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_ret_reg: Option<Regs>,
) -> Result<Option<EmulatorDriverResult<CM, ED, ET, S, SM>>, EmulatorDriverError> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
emu.modules_mut()
.modules_mut()
.allow_page_id_all(self.page_id);
@ -601,11 +572,11 @@ where
pub struct AddressAllowCommand {
address_range: Range<GuestAddr>,
}
impl<CM, ED, ET, S, SM> IsCommand<CM, ED, ET, S, SM> for AddressAllowCommand
impl<C, CM, ED, ET, I, S, SM> IsCommand<C, CM, ED, ET, I, S, SM> for AddressAllowCommand
where
ET: EmulatorModuleTuple<S>,
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput + Unpin,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
fn usable_at_runtime(&self) -> bool {
true
@ -613,11 +584,11 @@ where
fn run(
&self,
emu: &mut Emulator<CM, ED, ET, S, SM>,
emu: &mut Emulator<C, CM, ED, ET, I, S, SM>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_ret_reg: Option<Regs>,
) -> Result<Option<EmulatorDriverResult<CM, ED, ET, S, SM>>, EmulatorDriverError> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
emu.modules_mut()
.modules_mut()
.allow_address_range_all(self.address_range.clone());
@ -629,11 +600,11 @@ where
pub struct LqprintfCommand {
content: String,
}
impl<CM, ED, ET, S, SM> IsCommand<CM, ED, ET, S, SM> for LqprintfCommand
impl<C, CM, ED, ET, I, S, SM> IsCommand<C, CM, ED, ET, I, S, SM> for LqprintfCommand
where
ET: EmulatorModuleTuple<S>,
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput + Unpin,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
fn usable_at_runtime(&self) -> bool {
true
@ -641,11 +612,11 @@ where
fn run(
&self,
_emu: &mut Emulator<CM, ED, ET, S, SM>,
_emu: &mut Emulator<C, CM, ED, ET, I, S, SM>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_ret_reg: Option<Regs>,
) -> Result<Option<EmulatorDriverResult<CM, ED, ET, S, SM>>, EmulatorDriverError> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
print!("LQPRINTF: {}", self.content);
Ok(None)
}
@ -656,11 +627,11 @@ pub struct TestCommand {
expected_value: GuestReg,
received_value: GuestReg,
}
impl<CM, ED, ET, S, SM> IsCommand<CM, ED, ET, S, SM> for TestCommand
impl<C, CM, ED, ET, I, S, SM> IsCommand<C, CM, ED, ET, I, S, SM> for TestCommand
where
ET: EmulatorModuleTuple<S>,
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput + Unpin,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
fn usable_at_runtime(&self) -> bool {
true
@ -668,11 +639,11 @@ where
fn run(
&self,
_emu: &mut Emulator<CM, ED, ET, S, SM>,
_emu: &mut Emulator<C, CM, ED, ET, I, S, SM>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_ret_reg: Option<Regs>,
) -> Result<Option<EmulatorDriverResult<CM, ED, ET, S, SM>>, EmulatorDriverError> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
if self.expected_value == self.received_value {
Ok(None)
} else {

View File

@ -16,10 +16,7 @@ use std::{
};
use enum_map::EnumMap;
use libafl::{
executors::ExitKind,
inputs::{HasTargetBytes, UsesInput},
};
use libafl::{executors::ExitKind, inputs::HasTargetBytes};
use libafl_qemu_sys::{GuestAddr, GuestVirtAddr};
use libc::c_uint;
use paste::paste;
@ -99,11 +96,11 @@ macro_rules! define_nyx_command_manager {
}
}
impl<ET, S, SM> CommandManager<NyxEmulatorDriver, ET, S, SM> for $name<S>
impl<C, ET, I, S, SM> CommandManager<C, NyxEmulatorDriver, ET, I, S, SM> for $name<S>
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
type Commands = [<$name Commands>];
@ -121,7 +118,7 @@ macro_rules! define_nyx_command_manager {
match cmd_id {
// <StartPhysCommandParser as NativeCommandParser<S>>::COMMAND_ID => Ok(StdCommandManagerCommands::StartPhysCommandParserCmd(<StartPhysCommandParser as NativeCommandParser<S>>::parse(qemu, arch_regs_map)?)),
$(<$native_command_parser as NativeCommandParser<Self, NyxEmulatorDriver, ET, S, SM>>::COMMAND_ID => Ok(<$native_command_parser as NativeCommandParser<Self, NyxEmulatorDriver, ET, S, SM>>::parse(qemu, arch_regs_map)?.into())),+,
$(<$native_command_parser as NativeCommandParser<C, Self, NyxEmulatorDriver, ET, I, S, SM>>::COMMAND_ID => Ok(<$native_command_parser as NativeCommandParser<C, Self, NyxEmulatorDriver, ET, I, S, SM>>::parse(qemu, arch_regs_map)?.into())),+,
_ => Err(CommandError::UnknownCommand(cmd_id.into())),
}
}
@ -134,25 +131,25 @@ macro_rules! define_nyx_command_manager {
$($command($command)),+,
}
impl<ET, S, SM> IsCommand<$name<S>, NyxEmulatorDriver, ET, S, SM> for [<$name Commands>]
impl<C, ET, I, S, SM> IsCommand<C, $name<S>, NyxEmulatorDriver, ET, I, S, SM> for [<$name Commands>]
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
fn usable_at_runtime(&self) -> bool {
match self {
$([<$name Commands>]::$command(cmd) => <$command as IsCommand<$name<S>, NyxEmulatorDriver, ET, S, SM>>::usable_at_runtime(cmd)),+
$([<$name Commands>]::$command(cmd) => <$command as IsCommand<C, $name<S>, NyxEmulatorDriver, ET, I, S, SM>>::usable_at_runtime(cmd)),+
}
}
fn run(&self,
emu: &mut Emulator<$name<S>, NyxEmulatorDriver, ET, S, SM>,
emu: &mut Emulator<C, $name<S>, NyxEmulatorDriver, ET, I, S, SM>,
state: &mut S,
input: &S::Input,
input: &I,
ret_reg: Option<Regs>
) -> Result<Option<EmulatorDriverResult<$name<S>, NyxEmulatorDriver, ET, S, SM>>, EmulatorDriverError> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
match self {
$([<$name Commands>]::$command(cmd) => cmd.run(emu, state, input, ret_reg)),+
}
@ -204,22 +201,18 @@ define_nyx_command_manager!(
#[derive(Debug, Clone)]
pub struct AcquireCommand;
impl<CM, ED, ET, S, SM> IsCommand<CM, ED, ET, S, SM> for AcquireCommand
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
impl<C, CM, ED, ET, I, S, SM> IsCommand<C, CM, ED, ET, I, S, SM> for AcquireCommand {
fn usable_at_runtime(&self) -> bool {
false
}
fn run(
&self,
_emu: &mut Emulator<CM, ED, ET, S, SM>,
_emu: &mut Emulator<C, CM, ED, ET, I, S, SM>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_ret_reg: Option<Regs>,
) -> Result<Option<EmulatorDriverResult<CM, ED, ET, S, SM>>, EmulatorDriverError> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
Ok(None)
}
}
@ -238,11 +231,12 @@ impl GetPayloadCommand {
}
}
impl<ET, S, SM> IsCommand<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM> for GetPayloadCommand
impl<C, ET, I, S, SM> IsCommand<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for GetPayloadCommand
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
fn usable_at_runtime(&self) -> bool {
@ -251,14 +245,11 @@ where
fn run(
&self,
emu: &mut Emulator<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>,
emu: &mut Emulator<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_ret_reg: Option<Regs>,
) -> Result<
Option<EmulatorDriverResult<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>>,
EmulatorDriverError,
> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
let qemu = emu.qemu();
let struct_addr = self.input_struct_location;
@ -301,11 +292,12 @@ where
#[derive(Debug, Clone)]
pub struct NextPayloadCommand;
impl<ET, S, SM> IsCommand<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM> for NextPayloadCommand
impl<C, ET, I, S, SM> IsCommand<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for NextPayloadCommand
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
fn usable_at_runtime(&self) -> bool {
@ -314,14 +306,11 @@ where
fn run(
&self,
emu: &mut Emulator<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>,
emu: &mut Emulator<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>,
state: &mut S,
input: &S::Input,
input: &I,
_ret_reg: Option<Regs>,
) -> Result<
Option<EmulatorDriverResult<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>>,
EmulatorDriverError,
> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
let qemu = emu.qemu();
if !emu.command_manager_mut().start() {
@ -367,11 +356,12 @@ where
#[derive(Debug, Clone)]
pub struct SubmitCR3Command;
impl<ET, S, SM> IsCommand<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM> for SubmitCR3Command
impl<C, ET, I, S, SM> IsCommand<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for SubmitCR3Command
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
fn usable_at_runtime(&self) -> bool {
@ -380,14 +370,11 @@ where
fn run(
&self,
emu: &mut Emulator<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>,
emu: &mut Emulator<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_ret_reg: Option<Regs>,
) -> Result<
Option<EmulatorDriverResult<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>>,
EmulatorDriverError,
> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
let qemu = emu.qemu();
if let Some(current_cpu) = qemu.current_cpu() {
@ -417,11 +404,12 @@ impl RangeSubmitCommand {
}
}
impl<ET, S, SM> IsCommand<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM> for RangeSubmitCommand
impl<C, ET, I, S, SM> IsCommand<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for RangeSubmitCommand
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
fn usable_at_runtime(&self) -> bool {
@ -430,14 +418,11 @@ where
fn run(
&self,
emu: &mut Emulator<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>,
emu: &mut Emulator<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_ret_reg: Option<Regs>,
) -> Result<
Option<EmulatorDriverResult<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>>,
EmulatorDriverError,
> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
log::info!("Allow address range: {:#x?}", self.allowed_range);
const EMPTY_RANGE: Range<GuestAddr> = 0..0;
@ -457,11 +442,12 @@ where
#[derive(Debug, Clone)]
pub struct PanicCommand;
impl<ET, S, SM> IsCommand<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM> for PanicCommand
impl<C, ET, I, S, SM> IsCommand<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for PanicCommand
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
fn usable_at_runtime(&self) -> bool {
@ -470,14 +456,11 @@ where
fn run(
&self,
emu: &mut Emulator<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>,
emu: &mut Emulator<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_ret_reg: Option<Regs>,
) -> Result<
Option<EmulatorDriverResult<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>>,
EmulatorDriverError,
> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
let qemu = emu.qemu();
if !emu.command_manager_mut().has_started() {
@ -503,11 +486,12 @@ where
#[derive(Debug, Clone)]
pub struct SubmitPanicCommand;
impl<ET, S, SM> IsCommand<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM> for SubmitPanicCommand
impl<C, ET, I, S, SM> IsCommand<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for SubmitPanicCommand
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
fn usable_at_runtime(&self) -> bool {
@ -516,14 +500,11 @@ where
fn run(
&self,
_emu: &mut Emulator<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>,
_emu: &mut Emulator<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_ret_reg: Option<Regs>,
) -> Result<
Option<EmulatorDriverResult<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>>,
EmulatorDriverError,
> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
// TODO: add breakpoint to submit panic addr / page and associate it with a panic command
unimplemented!()
}
@ -540,11 +521,12 @@ impl UserAbortCommand {
}
}
impl<ET, S, SM> IsCommand<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM> for UserAbortCommand
impl<C, ET, I, S, SM> IsCommand<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for UserAbortCommand
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
fn usable_at_runtime(&self) -> bool {
@ -553,14 +535,11 @@ where
fn run(
&self,
_emu: &mut Emulator<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>,
_emu: &mut Emulator<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_ret_reg: Option<Regs>,
) -> Result<
Option<EmulatorDriverResult<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>>,
EmulatorDriverError,
> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
log::error!("Nyx Guest Abort: {}", self.content);
Ok(Some(EmulatorDriverResult::ShutdownRequest))
@ -569,11 +548,12 @@ where
#[derive(Debug, Clone)]
pub struct ReleaseCommand;
impl<ET, S, SM> IsCommand<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM> for ReleaseCommand
impl<C, ET, I, S, SM> IsCommand<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for ReleaseCommand
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
fn usable_at_runtime(&self) -> bool {
@ -582,14 +562,11 @@ where
fn run(
&self,
emu: &mut Emulator<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>,
emu: &mut Emulator<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_ret_reg: Option<Regs>,
) -> Result<
Option<EmulatorDriverResult<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>>,
EmulatorDriverError,
> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
let qemu = emu.qemu();
if emu.command_manager().has_started() {
@ -629,22 +606,18 @@ impl GetHostConfigCommand {
}
}
impl<CM, ED, ET, S, SM> IsCommand<CM, ED, ET, S, SM> for GetHostConfigCommand
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
impl<C, CM, ED, ET, I, S, SM> IsCommand<C, CM, ED, ET, I, S, SM> for GetHostConfigCommand {
fn usable_at_runtime(&self) -> bool {
false
}
fn run(
&self,
emu: &mut Emulator<CM, ED, ET, S, SM>,
emu: &mut Emulator<C, CM, ED, ET, I, S, SM>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_ret_reg: Option<Regs>,
) -> Result<Option<EmulatorDriverResult<CM, ED, ET, S, SM>>, EmulatorDriverError> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
// TODO: check this against fuzzer code
let host_config = bindings::host_config_t {
bitmap_size: 0,
@ -684,22 +657,18 @@ impl PrintfCommand {
}
}
impl<CM, ED, ET, S, SM> IsCommand<CM, ED, ET, S, SM> for PrintfCommand
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
impl<C, CM, ED, ET, I, S, SM> IsCommand<C, CM, ED, ET, I, S, SM> for PrintfCommand {
fn usable_at_runtime(&self) -> bool {
false
}
fn run(
&self,
_emu: &mut Emulator<CM, ED, ET, S, SM>,
_emu: &mut Emulator<C, CM, ED, ET, I, S, SM>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_ret_reg: Option<Regs>,
) -> Result<Option<EmulatorDriverResult<CM, ED, ET, S, SM>>, EmulatorDriverError> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
println!("hprintf: {}", self.content);
Ok(None)
}
@ -717,22 +686,18 @@ impl SetAgentConfigCommand {
}
}
impl<CM, ED, ET, S, SM> IsCommand<CM, ED, ET, S, SM> for SetAgentConfigCommand
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
impl<C, CM, ED, ET, I, S, SM> IsCommand<C, CM, ED, ET, I, S, SM> for SetAgentConfigCommand {
fn usable_at_runtime(&self) -> bool {
false
}
fn run(
&self,
_emu: &mut Emulator<CM, ED, ET, S, SM>,
_emu: &mut Emulator<C, CM, ED, ET, I, S, SM>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_ret_reg: Option<Regs>,
) -> Result<Option<EmulatorDriverResult<CM, ED, ET, S, SM>>, EmulatorDriverError> {
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
let agent_magic = self.agent_config.agent_magic;
let agent_version = self.agent_config.agent_version;

View File

@ -1,10 +1,7 @@
use std::{ffi::CStr, sync::OnceLock};
use enum_map::{enum_map, EnumMap};
use libafl::{
executors::ExitKind,
inputs::{HasTargetBytes, UsesInput},
};
use libafl::{executors::ExitKind, inputs::HasTargetBytes};
use libafl_qemu_sys::{GuestAddr, GuestPhysAddr, GuestVirtAddr};
use libc::c_uint;
@ -27,12 +24,8 @@ pub mod nyx;
pub static EMU_EXIT_KIND_MAP: OnceLock<EnumMap<NativeExitKind, Option<ExitKind>>> = OnceLock::new();
pub trait NativeCommandParser<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
type OutputCommand: IsCommand<CM, ED, ET, S, SM>;
pub trait NativeCommandParser<C, CM, ED, ET, I, S, SM> {
type OutputCommand: IsCommand<C, CM, ED, ET, I, S, SM>;
const COMMAND_ID: c_uint;
@ -43,11 +36,10 @@ where
}
pub struct InputPhysCommandParser;
impl<CM, ED, ET, S, SM> NativeCommandParser<CM, ED, ET, S, SM> for InputPhysCommandParser
impl<C, CM, ED, ET, I, S, SM> NativeCommandParser<C, CM, ED, ET, I, S, SM>
for InputPhysCommandParser
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
S::Input: HasTargetBytes,
I: HasTargetBytes,
{
type OutputCommand = InputCommand;
@ -72,11 +64,10 @@ where
}
pub struct InputVirtCommandParser;
impl<CM, ED, ET, S, SM> NativeCommandParser<CM, ED, ET, S, SM> for InputVirtCommandParser
impl<C, CM, ED, ET, I, S, SM> NativeCommandParser<C, CM, ED, ET, I, S, SM>
for InputVirtCommandParser
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
S::Input: HasTargetBytes,
I: HasTargetBytes,
{
type OutputCommand = InputCommand;
@ -98,12 +89,12 @@ where
pub struct StartPhysCommandParser;
impl<ET, S, SM> NativeCommandParser<StdCommandManager<S>, StdEmulatorDriver, ET, S, SM>
impl<C, ET, I, S, SM> NativeCommandParser<C, StdCommandManager<S>, StdEmulatorDriver, ET, I, S, SM>
for StartPhysCommandParser
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
type OutputCommand = StartCommand;
@ -127,12 +118,12 @@ where
pub struct StartVirtCommandParser;
impl<ET, S, SM> NativeCommandParser<StdCommandManager<S>, StdEmulatorDriver, ET, S, SM>
impl<C, ET, I, S, SM> NativeCommandParser<C, StdCommandManager<S>, StdEmulatorDriver, ET, I, S, SM>
for StartVirtCommandParser
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
type OutputCommand = StartCommand;
@ -155,11 +146,12 @@ where
}
pub struct SaveCommandParser;
impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorDriver, ET, S, SM> for SaveCommandParser
impl<C, CM, ET, I, S, SM> NativeCommandParser<C, CM, StdEmulatorDriver, ET, I, S, SM>
for SaveCommandParser
where
ET: EmulatorModuleTuple<S>,
CM: CommandManager<StdEmulatorDriver, ET, S, SM>,
S: UsesInput + Unpin,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
type OutputCommand = SaveCommand;
@ -175,10 +167,10 @@ where
}
pub struct LoadCommandParser;
impl<CM, ET, S, SM> NativeCommandParser<CM, StdEmulatorDriver, ET, S, SM> for LoadCommandParser
impl<C, CM, ET, I, S, SM> NativeCommandParser<C, CM, StdEmulatorDriver, ET, I, S, SM>
for LoadCommandParser
where
CM: CommandManager<StdEmulatorDriver, ET, S, SM>,
S: UsesInput,
CM: CommandManager<C, StdEmulatorDriver, ET, I, S, SM>,
SM: IsSnapshotManager,
{
type OutputCommand = LoadCommand;
@ -195,12 +187,12 @@ where
pub struct EndCommandParser;
impl<ET, S, SM> NativeCommandParser<StdCommandManager<S>, StdEmulatorDriver, ET, S, SM>
impl<C, ET, I, S, SM> NativeCommandParser<C, StdCommandManager<S>, StdEmulatorDriver, ET, I, S, SM>
for EndCommandParser
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
type OutputCommand = EndCommand;
@ -229,10 +221,8 @@ where
}
pub struct VersionCommandParser;
impl<CM, ED, ET, S, SM> NativeCommandParser<CM, ED, ET, S, SM> for VersionCommandParser
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
impl<C, CM, ED, ET, I, S, SM> NativeCommandParser<C, CM, ED, ET, I, S, SM>
for VersionCommandParser
{
type OutputCommand = VersionCommand;
@ -249,12 +239,12 @@ where
}
pub struct VaddrFilterAllowRangeCommandParser;
impl<CM, ED, ET, S, SM> NativeCommandParser<CM, ED, ET, S, SM>
impl<C, CM, ED, ET, I, S, SM> NativeCommandParser<C, CM, ED, ET, I, S, SM>
for VaddrFilterAllowRangeCommandParser
where
ET: EmulatorModuleTuple<S>,
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput + Unpin,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
type OutputCommand = AddressAllowCommand;
@ -272,11 +262,11 @@ where
}
pub struct LqprintfCommandParser;
impl<CM, ED, ET, S, SM> NativeCommandParser<CM, ED, ET, S, SM> for LqprintfCommandParser
impl<C, CM, ED, ET, I, S, SM> NativeCommandParser<C, CM, ED, ET, I, S, SM> for LqprintfCommandParser
where
ET: EmulatorModuleTuple<S>,
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput + Unpin,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
type OutputCommand = LqprintfCommand;
const COMMAND_ID: c_uint = bindings::LibaflQemuCommand_LIBAFL_QEMU_COMMAND_LQPRINTF.0;
@ -306,11 +296,11 @@ where
}
pub struct TestCommandParser;
impl<CM, ED, ET, S, SM> NativeCommandParser<CM, ED, ET, S, SM> for TestCommandParser
impl<C, CM, ED, ET, I, S, SM> NativeCommandParser<C, CM, ED, ET, I, S, SM> for TestCommandParser
where
ET: EmulatorModuleTuple<S>,
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput + Unpin,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
type OutputCommand = TestCommand;
const COMMAND_ID: c_uint = bindings::LibaflQemuCommand_LIBAFL_QEMU_COMMAND_TEST.0;

View File

@ -1,10 +1,7 @@
use std::{ffi::CStr, sync::OnceLock};
use enum_map::EnumMap;
use libafl::{
executors::ExitKind,
inputs::{HasTargetBytes, UsesInput},
};
use libafl::{executors::ExitKind, inputs::HasTargetBytes};
use libafl_qemu_sys::GuestVirtAddr;
use libc::c_uint;
@ -16,7 +13,7 @@ use crate::{
SetAgentConfigCommand, SubmitCR3Command, SubmitPanicCommand, UserAbortCommand,
},
parser::NativeCommandParser,
CommandError, CommandManager, NativeExitKind,
CommandError, NativeExitKind,
},
modules::EmulatorModuleTuple,
sync_exit::ExitArgs,
@ -40,11 +37,9 @@ fn get_guest_string(qemu: Qemu, string_ptr_reg: Regs) -> Result<String, CommandE
pub static EMU_EXIT_KIND_MAP: OnceLock<EnumMap<NativeExitKind, Option<ExitKind>>> = OnceLock::new();
pub struct AcquireCommandParser;
impl<CM, ED, ET, S, SM> NativeCommandParser<CM, ED, ET, S, SM> for AcquireCommandParser
impl<C, CM, ED, ET, I, S, SM> NativeCommandParser<C, CM, ED, ET, I, S, SM> for AcquireCommandParser
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
S::Input: HasTargetBytes,
I: HasTargetBytes,
{
type OutputCommand = AcquireCommand;
@ -59,12 +54,12 @@ where
}
pub struct GetPayloadCommandParser;
impl<ET, S, SM> NativeCommandParser<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>
impl<C, ET, I, S, SM> NativeCommandParser<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for GetPayloadCommandParser
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
type OutputCommand = GetPayloadCommand;
@ -82,12 +77,12 @@ where
}
pub struct SubmitCR3CommandParser;
impl<ET, S, SM> NativeCommandParser<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>
impl<C, ET, I, S, SM> NativeCommandParser<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for SubmitCR3CommandParser
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
type OutputCommand = SubmitCR3Command;
@ -102,12 +97,12 @@ where
}
pub struct RangeSubmitCommandParser;
impl<ET, S, SM> NativeCommandParser<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>
impl<C, ET, I, S, SM> NativeCommandParser<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for RangeSubmitCommandParser
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
type OutputCommand = RangeSubmitCommand;
@ -128,12 +123,12 @@ where
}
pub struct SubmitPanicCommandParser;
impl<ET, S, SM> NativeCommandParser<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>
impl<C, ET, I, S, SM> NativeCommandParser<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for SubmitPanicCommandParser
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
type OutputCommand = SubmitPanicCommand;
@ -148,12 +143,12 @@ where
}
pub struct PanicCommandParser;
impl<ET, S, SM> NativeCommandParser<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>
impl<C, ET, I, S, SM> NativeCommandParser<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for PanicCommandParser
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
type OutputCommand = PanicCommand;
@ -168,12 +163,12 @@ where
}
pub struct UserAbortCommandParser;
impl<ET, S, SM> NativeCommandParser<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>
impl<C, ET, I, S, SM> NativeCommandParser<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for UserAbortCommandParser
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
type OutputCommand = UserAbortCommand;
@ -190,12 +185,12 @@ where
}
pub struct NextPayloadCommandParser;
impl<ET, S, SM> NativeCommandParser<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>
impl<C, ET, I, S, SM> NativeCommandParser<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for NextPayloadCommandParser
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
type OutputCommand = NextPayloadCommand;
@ -211,12 +206,12 @@ where
}
pub struct ReleaseCommandParser;
impl<ET, S, SM> NativeCommandParser<NyxCommandManager<S>, NyxEmulatorDriver, ET, S, SM>
impl<C, ET, I, S, SM> NativeCommandParser<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for ReleaseCommandParser
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
type OutputCommand = ReleaseCommand;
@ -232,11 +227,10 @@ where
}
pub struct GetHostConfigCommandParser;
impl<CM, ED, ET, S, SM> NativeCommandParser<CM, ED, ET, S, SM> for GetHostConfigCommandParser
impl<C, CM, ED, ET, I, S, SM> NativeCommandParser<C, CM, ED, ET, I, S, SM>
for GetHostConfigCommandParser
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
S::Input: HasTargetBytes,
I: HasTargetBytes,
{
type OutputCommand = GetHostConfigCommand;
@ -257,11 +251,10 @@ where
}
pub struct SetAgentConfigCommandParser;
impl<CM, ED, ET, S, SM> NativeCommandParser<CM, ED, ET, S, SM> for SetAgentConfigCommandParser
impl<C, CM, ED, ET, I, S, SM> NativeCommandParser<C, CM, ED, ET, I, S, SM>
for SetAgentConfigCommandParser
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
S::Input: HasTargetBytes,
I: HasTargetBytes,
{
type OutputCommand = SetAgentConfigCommand;
@ -283,11 +276,9 @@ where
}
pub struct PrintfCommandParser;
impl<CM, ED, ET, S, SM> NativeCommandParser<CM, ED, ET, S, SM> for PrintfCommandParser
impl<C, CM, ED, ET, I, S, SM> NativeCommandParser<C, CM, ED, ET, I, S, SM> for PrintfCommandParser
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
S::Input: HasTargetBytes,
I: HasTargetBytes,
{
type OutputCommand = PrintfCommand;

View File

@ -1,7 +1,7 @@
use std::marker::PhantomData;
use libafl::{
inputs::{HasTargetBytes, UsesInput},
inputs::HasTargetBytes,
state::{HasExecutions, State},
};
use libafl_bolts::tuples::{tuple_list, Append, Prepend};
@ -9,7 +9,7 @@ use libafl_bolts::tuples::{tuple_list, Append, Prepend};
#[cfg(feature = "systemmode")]
use crate::FastSnapshotManager;
use crate::{
command::{CommandManager, NopCommandManager, StdCommandManager},
command::{NopCommandManager, StdCommandManager},
config::QemuConfigBuilder,
modules::{EmulatorModule, EmulatorModuleTuple},
Emulator, NopEmulatorDriver, NopSnapshotManager, QemuInitError, QemuParams, StdEmulatorDriver,
@ -27,29 +27,26 @@ use crate::{config::QemuConfig, Qemu};
/// - with a QEMU-compatible CLI. It will be given to QEMU as-is. The first argument should always be a path to the running binary, as expected by execve.
/// - with an instance of [`QemuConfig`]. It is a more programmatic way to configure [`Qemu`]. It should be built using [`QemuConfigBuilder`].
#[derive(Clone)]
pub struct EmulatorBuilder<CM, ED, ET, QP, S, SM>
where
S: UsesInput,
{
pub struct EmulatorBuilder<C, CM, ED, ET, QP, I, S, SM> {
modules: ET,
driver: ED,
snapshot_manager: SM,
command_manager: CM,
qemu_parameters: Option<QP>,
phantom: PhantomData<S>,
phantom: PhantomData<(C, I, S)>,
}
impl<S>
impl<C, I, S>
EmulatorBuilder<
C,
NopCommandManager,
NopEmulatorDriver,
(),
QemuConfigBuilder,
I,
S,
NopSnapshotManager,
>
where
S: UsesInput,
{
#[must_use]
pub fn empty() -> Self {
@ -65,18 +62,20 @@ where
}
#[cfg(feature = "usermode")]
impl<S>
impl<C, I, S>
EmulatorBuilder<
C,
StdCommandManager<S>,
StdEmulatorDriver,
(),
QemuConfigBuilder,
I,
S,
StdSnapshotManager,
>
where
S: State + HasExecutions + Unpin,
S::Input: HasTargetBytes,
I: HasTargetBytes,
{
#[must_use]
#[expect(clippy::should_implement_trait)]
@ -93,18 +92,20 @@ where
}
#[cfg(feature = "systemmode")]
impl<S>
impl<C, I, S>
EmulatorBuilder<
C,
StdCommandManager<S>,
StdEmulatorDriver,
(),
QemuConfigBuilder,
I,
S,
StdSnapshotManager,
>
where
S: State + HasExecutions + Unpin,
S::Input: HasTargetBytes,
I: HasTargetBytes,
{
#[expect(clippy::should_implement_trait)]
#[must_use]
@ -119,9 +120,10 @@ where
}
}
}
impl<CM, ED, ET, QP, S, SM> EmulatorBuilder<CM, ED, ET, QP, S, SM>
impl<C, CM, ED, ET, QP, I, S, SM> EmulatorBuilder<C, CM, ED, ET, QP, I, S, SM>
where
S: UsesInput + Unpin,
I: Unpin,
S: Unpin,
{
fn new(
modules: ET,
@ -140,10 +142,10 @@ where
}
}
pub fn build<E>(self) -> Result<Emulator<CM, ED, ET, S, SM>, QemuInitError>
#[allow(clippy::type_complexity)]
pub fn build<E>(self) -> Result<Emulator<C, CM, ED, ET, I, S, SM>, QemuInitError>
where
CM: CommandManager<ED, ET, S, SM>,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
QP: TryInto<QemuParams, Error = E>,
QemuInitError: From<E>,
{
@ -162,16 +164,16 @@ where
}
}
impl<CM, ED, ET, QP, S, SM> EmulatorBuilder<CM, ED, ET, QP, S, SM>
impl<C, CM, ED, ET, QP, I, S, SM> EmulatorBuilder<C, CM, ED, ET, QP, I, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput + Unpin,
I: Unpin,
S: Unpin,
{
#[must_use]
pub fn qemu_parameters<QP2>(
self,
qemu_parameters: QP2,
) -> EmulatorBuilder<CM, ED, ET, QP2, S, SM>
) -> EmulatorBuilder<C, CM, ED, ET, QP2, I, S, SM>
where
QP2: Into<QemuParams>,
{
@ -184,10 +186,13 @@ where
)
}
pub fn prepend_module<EM>(self, module: EM) -> EmulatorBuilder<CM, ED, (EM, ET), QP, S, SM>
pub fn prepend_module<EM>(
self,
module: EM,
) -> EmulatorBuilder<C, CM, ED, (EM, ET), QP, I, S, SM>
where
EM: EmulatorModule<S> + Unpin,
ET: EmulatorModuleTuple<S>,
EM: EmulatorModule<I, S> + Unpin,
ET: EmulatorModuleTuple<I, S>,
{
EmulatorBuilder::new(
self.modules.prepend(module),
@ -198,10 +203,10 @@ where
)
}
pub fn append_module<EM>(self, module: EM) -> EmulatorBuilder<CM, ED, (ET, EM), QP, S, SM>
pub fn append_module<EM>(self, module: EM) -> EmulatorBuilder<C, CM, ED, (ET, EM), QP, I, S, SM>
where
EM: EmulatorModule<S> + Unpin,
ET: EmulatorModuleTuple<S>,
EM: EmulatorModule<I, S> + Unpin,
ET: EmulatorModuleTuple<I, S>,
{
EmulatorBuilder::new(
self.modules.append(module),
@ -212,7 +217,7 @@ where
)
}
pub fn driver<ED2>(self, driver: ED2) -> EmulatorBuilder<CM, ED2, ET, QP, S, SM> {
pub fn driver<ED2>(self, driver: ED2) -> EmulatorBuilder<C, CM, ED2, ET, QP, I, S, SM> {
EmulatorBuilder::new(
self.modules,
driver,
@ -225,10 +230,7 @@ where
pub fn command_manager<CM2>(
self,
command_manager: CM2,
) -> EmulatorBuilder<CM2, ED, ET, QP, S, SM>
where
CM2: CommandManager<ED, ET, S, SM>,
{
) -> EmulatorBuilder<C, CM2, ED, ET, QP, I, S, SM> {
EmulatorBuilder::new(
self.modules,
self.driver,
@ -238,7 +240,7 @@ where
)
}
pub fn modules<ET2>(self, modules: ET2) -> EmulatorBuilder<CM, ED, ET2, QP, S, SM> {
pub fn modules<ET2>(self, modules: ET2) -> EmulatorBuilder<C, CM, ED, ET2, QP, I, S, SM> {
EmulatorBuilder::new(
modules,
self.driver,
@ -251,7 +253,7 @@ where
pub fn snapshot_manager<SM2>(
self,
snapshot_manager: SM2,
) -> EmulatorBuilder<CM, ED, ET, QP, S, SM2> {
) -> EmulatorBuilder<C, CM, ED, ET, QP, I, S, SM2> {
EmulatorBuilder::new(
self.modules,
self.driver,

View File

@ -3,11 +3,7 @@
use std::{cell::OnceCell, fmt::Debug};
use libafl::{
executors::ExitKind,
inputs::{HasTargetBytes, UsesInput},
observers::ObserversTuple,
};
use libafl::{executors::ExitKind, inputs::HasTargetBytes, observers::ObserversTuple};
use libafl_bolts::os::{unix_signals::Signal, CTRL_C_EXIT};
use typed_builder::TypedBuilder;
@ -30,13 +26,9 @@ pub mod nyx;
pub use nyx::{NyxEmulatorDriver, NyxEmulatorDriverBuilder};
#[derive(Debug, Clone)]
pub enum EmulatorDriverResult<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
pub enum EmulatorDriverResult<C> {
/// Return to the harness immediately. Can happen at any point of the run when the handler is not supposed to handle a request.
ReturnToHarness(EmulatorExitResult<CM, ED, ET, S, SM>),
ReturnToHarness(EmulatorExitResult<C>),
/// The run is over and the emulator is ready for the next iteration.
EndOfRun(ExitKind),
@ -66,36 +58,37 @@ impl From<QemuError> for EmulatorDriverError {
/// An Emulator Driver.
// TODO remove 'static when specialization will be stable
pub trait EmulatorDriver<CM, ET, S, SM>: 'static + Sized
pub trait EmulatorDriver<C, CM, ET, I, S, SM>: 'static + Sized
where
CM: CommandManager<Self, ET, S, SM>,
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
C: Clone,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
/// Just before calling user's harness for the first time.
/// Called only once
fn first_harness_exec(emulator: &mut Emulator<CM, Self, ET, S, SM>, state: &mut S) {
fn first_harness_exec(emulator: &mut Emulator<C, CM, Self, ET, I, S, SM>, state: &mut S) {
emulator.modules.first_exec_all(emulator.qemu, state);
}
/// Just before calling user's harness
fn pre_harness_exec(
emulator: &mut Emulator<CM, Self, ET, S, SM>,
emulator: &mut Emulator<C, CM, Self, ET, I, S, SM>,
state: &mut S,
input: &S::Input,
input: &I,
) {
emulator.modules.pre_exec_all(emulator.qemu, state, input);
}
/// Just after returning from user's harness
fn post_harness_exec<OT>(
emulator: &mut Emulator<CM, Self, ET, S, SM>,
input: &S::Input,
emulator: &mut Emulator<C, CM, Self, ET, I, S, SM>,
input: &I,
observers: &mut OT,
state: &mut S,
exit_kind: &mut ExitKind,
) where
OT: ObserversTuple<S::Input, S>,
OT: ObserversTuple<I, S>,
{
emulator
.modules
@ -103,16 +96,15 @@ where
}
/// Just before entering QEMU
fn pre_qemu_exec(_emulator: &mut Emulator<CM, Self, ET, S, SM>, _input: &S::Input) {}
fn pre_qemu_exec(_emulator: &mut Emulator<C, CM, Self, ET, I, S, SM>, _input: &I) {}
/// Just after QEMU exits
#[expect(clippy::type_complexity)]
fn post_qemu_exec(
_emulator: &mut Emulator<CM, Self, ET, S, SM>,
_emulator: &mut Emulator<C, CM, Self, ET, I, S, SM>,
_state: &mut S,
exit_reason: &mut Result<EmulatorExitResult<CM, Self, ET, S, SM>, EmulatorExitError>,
_input: &S::Input,
) -> Result<Option<EmulatorDriverResult<CM, Self, ET, S, SM>>, EmulatorDriverError> {
exit_reason: &mut Result<EmulatorExitResult<C>, EmulatorExitError>,
_input: &I,
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
match exit_reason {
Ok(reason) => Ok(Some(EmulatorDriverResult::ReturnToHarness(reason.clone()))),
Err(error) => Err(error.clone().into()),
@ -121,11 +113,12 @@ where
}
pub struct NopEmulatorDriver;
impl<CM, ET, S, SM> EmulatorDriver<CM, ET, S, SM> for NopEmulatorDriver
impl<C, CM, ET, I, S, SM> EmulatorDriver<C, CM, ET, I, S, SM> for NopEmulatorDriver
where
CM: CommandManager<Self, ET, S, SM>,
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
C: Clone,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
}
@ -180,24 +173,25 @@ impl StdEmulatorDriver {
}
// TODO: replace handlers with generics to permit compile-time customization of handlers
impl<CM, ET, S, SM> EmulatorDriver<CM, ET, S, SM> for StdEmulatorDriver
impl<C, CM, ET, I, S, SM> EmulatorDriver<C, CM, ET, I, S, SM> for StdEmulatorDriver
where
CM: CommandManager<StdEmulatorDriver, ET, S, SM>,
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
C: IsCommand<CM::Commands, CM, Self, ET, I, S, SM>,
CM: CommandManager<C, Self, ET, I, S, SM, Commands = C>,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
fn first_harness_exec(emulator: &mut Emulator<CM, Self, ET, S, SM>, state: &mut S) {
fn first_harness_exec(emulator: &mut Emulator<C, CM, Self, ET, I, S, SM>, state: &mut S) {
if !emulator.driver.hooks_locked {
emulator.modules.first_exec_all(emulator.qemu, state);
}
}
fn pre_harness_exec(
emulator: &mut Emulator<CM, Self, ET, S, SM>,
emulator: &mut Emulator<C, CM, Self, ET, I, S, SM>,
state: &mut S,
input: &S::Input,
input: &I,
) {
if !emulator.driver.hooks_locked {
emulator.modules.pre_exec_all(emulator.qemu, state, input);
@ -216,13 +210,13 @@ where
}
fn post_harness_exec<OT>(
emulator: &mut Emulator<CM, Self, ET, S, SM>,
input: &S::Input,
emulator: &mut Emulator<C, CM, Self, ET, I, S, SM>,
input: &I,
observers: &mut OT,
state: &mut S,
exit_kind: &mut ExitKind,
) where
OT: ObserversTuple<S::Input, S>,
OT: ObserversTuple<I, S>,
{
if !emulator.driver.hooks_locked {
emulator
@ -231,16 +225,17 @@ where
}
}
fn pre_qemu_exec(_emulator: &mut Emulator<CM, Self, ET, S, SM>, _input: &S::Input) {}
fn pre_qemu_exec(_emulator: &mut Emulator<C, CM, Self, ET, I, S, SM>, _input: &I) {}
fn post_qemu_exec(
emulator: &mut Emulator<CM, Self, ET, S, SM>,
emulator: &mut Emulator<C, CM, Self, ET, I, S, SM>,
state: &mut S,
exit_reason: &mut Result<EmulatorExitResult<CM, Self, ET, S, SM>, EmulatorExitError>,
input: &S::Input,
) -> Result<Option<EmulatorDriverResult<CM, Self, ET, S, SM>>, EmulatorDriverError> {
exit_reason: &mut Result<EmulatorExitResult<C>, EmulatorExitError>,
input: &I,
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
let qemu = emulator.qemu();
// Check if QEMU existed because of an error or to handle some request
let mut exit_reason = match exit_reason {
Ok(exit_reason) => exit_reason,
Err(exit_error) => match exit_error {
@ -254,7 +249,8 @@ where
},
};
let (command, ret_reg): (Option<CM::Commands>, Option<Regs>) = match &mut exit_reason {
// If QEMU stopped because of a request, handle it here
let (command, ret_reg): (Option<C>, Option<Regs>) = match &mut exit_reason {
EmulatorExitResult::QemuExit(shutdown_cause) => match shutdown_cause {
QemuShutdownCause::HostSignal(signal) => {
signal.handle();
@ -279,6 +275,7 @@ where
}
};
// If QEMU requested to handle a command, run it here.
if let Some(cmd) = command {
if emulator.driver.print_commands {
println!("Received command: {cmd:?}");
@ -292,14 +289,13 @@ where
}
}
impl<CM, ED, ET, S, SM> TryFrom<EmulatorDriverResult<CM, ED, ET, S, SM>> for ExitKind
impl<C> TryFrom<EmulatorDriverResult<C>> for ExitKind
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
C: Debug,
{
type Error = String;
fn try_from(value: EmulatorDriverResult<CM, ED, ET, S, SM>) -> Result<Self, Self::Error> {
fn try_from(value: EmulatorDriverResult<C>) -> Result<Self, Self::Error> {
match value {
EmulatorDriverResult::ReturnToHarness(unhandled_qemu_exit) => {
Err(format!("Unhandled QEMU exit: {:?}", &unhandled_qemu_exit))

View File

@ -1,10 +1,6 @@
use std::{cell::OnceCell, cmp::min, ptr, slice::from_raw_parts};
use libafl::{
executors::ExitKind,
inputs::{HasTargetBytes, UsesInput},
observers::ObserversTuple,
};
use libafl::{executors::ExitKind, inputs::HasTargetBytes, observers::ObserversTuple};
use libafl_bolts::os::CTRL_C_EXIT;
use typed_builder::TypedBuilder;
@ -107,24 +103,25 @@ impl NyxEmulatorDriver {
}
}
impl<CM, ET, S, SM> EmulatorDriver<CM, ET, S, SM> for NyxEmulatorDriver
impl<C, CM, ET, I, S, SM> EmulatorDriver<C, CM, ET, I, S, SM> for NyxEmulatorDriver
where
CM: CommandManager<NyxEmulatorDriver, ET, S, SM>,
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
S::Input: HasTargetBytes,
C: IsCommand<CM::Commands, CM, Self, ET, I, S, SM>,
CM: CommandManager<C, Self, ET, I, S, SM, Commands = C>,
ET: EmulatorModuleTuple<I, S>,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
{
fn first_harness_exec(emulator: &mut Emulator<CM, Self, ET, S, SM>, state: &mut S) {
fn first_harness_exec(emulator: &mut Emulator<C, CM, Self, ET, I, S, SM>, state: &mut S) {
if !emulator.driver.hooks_locked {
emulator.modules.first_exec_all(emulator.qemu, state);
}
}
fn pre_harness_exec(
emulator: &mut Emulator<CM, Self, ET, S, SM>,
emulator: &mut Emulator<C, CM, Self, ET, I, S, SM>,
state: &mut S,
input: &S::Input,
input: &I,
) {
if !emulator.driver.hooks_locked {
emulator.modules.pre_exec_all(emulator.qemu, state, input);
@ -138,13 +135,13 @@ where
}
fn post_harness_exec<OT>(
emulator: &mut Emulator<CM, Self, ET, S, SM>,
input: &S::Input,
emulator: &mut Emulator<C, CM, Self, ET, I, S, SM>,
input: &I,
observers: &mut OT,
state: &mut S,
exit_kind: &mut ExitKind,
) where
OT: ObserversTuple<S::Input, S>,
OT: ObserversTuple<I, S>,
{
if !emulator.driver.hooks_locked {
emulator
@ -153,14 +150,14 @@ where
}
}
fn pre_qemu_exec(_emulator: &mut Emulator<CM, Self, ET, S, SM>, _input: &S::Input) {}
fn pre_qemu_exec(_emulator: &mut Emulator<C, CM, Self, ET, I, S, SM>, _input: &I) {}
fn post_qemu_exec(
emulator: &mut Emulator<CM, Self, ET, S, SM>,
emulator: &mut Emulator<C, CM, Self, ET, I, S, SM>,
state: &mut S,
exit_reason: &mut Result<EmulatorExitResult<CM, Self, ET, S, SM>, EmulatorExitError>,
input: &S::Input,
) -> Result<Option<EmulatorDriverResult<CM, Self, ET, S, SM>>, EmulatorDriverError> {
exit_reason: &mut Result<EmulatorExitResult<C>, EmulatorExitError>,
input: &I,
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
let qemu = emulator.qemu();
let mut exit_reason = match exit_reason {
@ -176,7 +173,7 @@ where
},
};
let (command, ret_reg): (Option<CM::Commands>, Option<Regs>) = match &mut exit_reason {
let (command, ret_reg): (Option<C>, Option<Regs>) = match &mut exit_reason {
EmulatorExitResult::QemuExit(shutdown_cause) => match shutdown_cause {
QemuShutdownCause::HostSignal(signal) => {
signal.handle();

View File

@ -2,7 +2,7 @@
use std::{fmt::Debug, marker::PhantomData, mem::transmute, pin::Pin, ptr};
use libafl::{executors::ExitKind, inputs::UsesInput, observers::ObserversTuple};
use libafl::{executors::ExitKind, observers::ObserversTuple};
use libafl_qemu_sys::{CPUStatePtr, FatPtr, GuestAddr, GuestUsize, TCGTemp};
#[cfg(feature = "usermode")]
@ -73,13 +73,13 @@ macro_rules! hook_to_repr {
static mut EMULATOR_MODULES: *mut () = ptr::null_mut();
#[cfg(feature = "usermode")]
pub extern "C" fn crash_hook_wrapper<ET, S>(target_sig: i32)
pub extern "C" fn crash_hook_wrapper<ET, I, S>(target_sig: i32)
where
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<I, S>,
S: Unpin,
{
unsafe {
let emulator_modules = EmulatorModules::<ET, S>::emulator_modules_mut().unwrap();
let emulator_modules = EmulatorModules::<ET, I, S>::emulator_modules_mut().unwrap();
let qemu = Qemu::get_unchecked();
let crash_hooks_ptr = &raw mut emulator_modules.hooks.hook_collection.crash_hooks;
@ -87,12 +87,12 @@ where
for crash_hook in &mut (*crash_hooks_ptr) {
match crash_hook {
HookRepr::Function(ptr) => {
let func: CrashHookFn<ET, S> = transmute(*ptr);
let func: CrashHookFn<ET, I, S> = transmute(*ptr);
func(qemu, emulator_modules, target_sig);
}
HookRepr::Closure(ptr) => {
let func: &mut CrashHookClosure<ET, S> =
&mut *(ptr::from_mut::<FatPtr>(ptr) as *mut CrashHookClosure<ET, S>);
let func: &mut CrashHookClosure<ET, I, S> =
&mut *(ptr::from_mut::<FatPtr>(ptr) as *mut CrashHookClosure<ET, I, S>);
func(qemu, emulator_modules, target_sig);
}
HookRepr::Empty => (),
@ -103,14 +103,13 @@ where
/// High-level `Emulator` modules, using `QemuHooks`.
#[derive(Debug)]
pub struct EmulatorModules<ET, S> {
pub struct EmulatorModules<ET, I, S> {
modules: Pin<Box<ET>>,
hooks: EmulatorHooks<ET, S>,
phantom: PhantomData<S>,
hooks: EmulatorHooks<ET, I, S>,
}
#[derive(Debug)]
struct EmulatorHookCollection<ET, S> {
struct EmulatorHookCollection<ET, I, S> {
instruction_hooks: Vec<Pin<Box<(InstructionHookId, FatPtr)>>>,
backdoor_hooks: Vec<Pin<Box<(BackdoorHookId, FatPtr)>>>,
edge_hooks: Vec<Pin<Box<TcgHookState<1, EdgeHookId>>>>,
@ -132,10 +131,10 @@ struct EmulatorHookCollection<ET, S> {
#[cfg(feature = "usermode")]
crash_hooks: Vec<HookRepr>,
phantom: PhantomData<(ET, S)>,
phantom: PhantomData<(ET, I, S)>,
}
impl<ET, S> Default for EmulatorHookCollection<ET, S> {
impl<ET, I, S> Default for EmulatorHookCollection<ET, I, S> {
fn default() -> Self {
Self {
instruction_hooks: Vec::default(),
@ -166,14 +165,15 @@ impl<ET, S> Default for EmulatorHookCollection<ET, S> {
/// Hook collection,
#[derive(Debug)]
pub struct EmulatorHooks<ET, S> {
pub struct EmulatorHooks<ET, I, S> {
qemu_hooks: QemuHooks,
hook_collection: EmulatorHookCollection<ET, S>,
hook_collection: EmulatorHookCollection<ET, I, S>,
}
impl<ET, S> EmulatorHooks<ET, S>
impl<ET, I, S> EmulatorHooks<ET, I, S>
where
S: UsesInput + Unpin,
I: Unpin,
S: Unpin,
{
#[must_use]
pub fn new(qemu_hooks: QemuHooks) -> Self {
@ -191,7 +191,7 @@ where
pub fn instruction_closure(
&mut self,
addr: GuestAddr,
hook: InstructionHookClosure<ET, S>,
hook: InstructionHookClosure<ET, I, S>,
invalidate_block: bool,
) -> InstructionHookId {
let fat: FatPtr = unsafe { transmute(hook) };
@ -213,7 +213,7 @@ where
let id = self.qemu_hooks.add_instruction_hooks(
&mut *hook_state,
addr,
closure_instruction_hook_wrapper::<ET, S>,
closure_instruction_hook_wrapper::<ET, I, S>,
invalidate_block,
);
self.hook_collection
@ -230,7 +230,7 @@ where
pub fn instructions(
&mut self,
addr: GuestAddr,
hook: InstructionHook<ET, S>,
hook: InstructionHook<ET, I, S>,
invalidate_block: bool,
) -> Option<InstructionHookId> {
match hook {
@ -250,14 +250,14 @@ where
pub fn instruction_function(
&mut self,
addr: GuestAddr,
hook: InstructionHookFn<ET, S>,
hook: InstructionHookFn<ET, I, S>,
invalidate_block: bool,
) -> InstructionHookId {
unsafe {
self.qemu_hooks.add_instruction_hooks(
transmute(hook),
addr,
func_instruction_hook_wrapper::<ET, S>,
func_instruction_hook_wrapper::<ET, I, S>,
invalidate_block,
)
}
@ -265,13 +265,13 @@ where
pub fn edges(
&mut self,
generation_hook: EdgeGenHook<ET, S>,
execution_hook: EdgeExecHook<ET, S>,
generation_hook: EdgeGenHook<ET, I, S>,
execution_hook: EdgeExecHook<ET, I, S>,
) -> EdgeHookId {
unsafe {
let gen = get_raw_hook!(
generation_hook,
edge_gen_hook_wrapper::<ET, S>,
edge_gen_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(
&mut TcgHookState<1, EdgeHookId>,
src: GuestAddr,
@ -281,7 +281,7 @@ where
let exec = get_raw_hook!(
execution_hook,
edge_0_exec_hook_wrapper::<ET, S>,
edge_0_exec_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(&mut TcgHookState<1, EdgeHookId>, id: u64)
);
@ -319,20 +319,20 @@ where
pub fn blocks(
&mut self,
generation_hook: BlockGenHook<ET, S>,
post_generation_hook: BlockPostGenHook<ET, S>,
execution_hook: BlockExecHook<ET, S>,
generation_hook: BlockGenHook<ET, I, S>,
post_generation_hook: BlockPostGenHook<ET, I, S>,
execution_hook: BlockExecHook<ET, I, S>,
) -> BlockHookId {
unsafe {
let gen = get_raw_hook!(
generation_hook,
block_gen_hook_wrapper::<ET, S>,
block_gen_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(&mut TcgHookState<1, BlockHookId>, pc: GuestAddr) -> u64
);
let postgen = get_raw_hook!(
post_generation_hook,
block_post_gen_hook_wrapper::<ET, S>,
block_post_gen_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(
&mut TcgHookState<1, BlockHookId>,
pc: GuestAddr,
@ -342,7 +342,7 @@ where
let exec = get_raw_hook!(
execution_hook,
block_0_exec_hook_wrapper::<ET, S>,
block_0_exec_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(&mut TcgHookState<1, BlockHookId>, id: u64)
);
@ -382,19 +382,19 @@ where
pub fn cpu_runs(
&mut self,
pre_exec_hook: CpuPreRunHook<ET, S>,
post_exec_hook: CpuPostRunHook<ET, S>,
pre_exec_hook: CpuPreRunHook<ET, I, S>,
post_exec_hook: CpuPostRunHook<ET, I, S>,
) -> CpuRunHookId {
unsafe {
let pre_run = get_raw_hook!(
pre_exec_hook,
cpu_run_pre_exec_hook_wrapper::<ET, S>,
cpu_run_pre_exec_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(&mut HookState<CpuRunHookId>, cpu: CPUStatePtr)
);
let post_run = get_raw_hook!(
post_exec_hook,
cpu_run_post_exec_hook_wrapper::<ET, S>,
cpu_run_post_exec_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(&mut HookState<CpuRunHookId>, cpu: CPUStatePtr)
);
@ -434,17 +434,17 @@ where
#[expect(clippy::similar_names)]
pub fn reads(
&mut self,
generation_hook: ReadGenHook<ET, S>,
execution_hook_1: ReadExecHook<ET, S>,
execution_hook_2: ReadExecHook<ET, S>,
execution_hook_4: ReadExecHook<ET, S>,
execution_hook_8: ReadExecHook<ET, S>,
execution_hook_n: ReadExecNHook<ET, S>,
generation_hook: ReadGenHook<ET, I, S>,
execution_hook_1: ReadExecHook<ET, I, S>,
execution_hook_2: ReadExecHook<ET, I, S>,
execution_hook_4: ReadExecHook<ET, I, S>,
execution_hook_8: ReadExecHook<ET, I, S>,
execution_hook_n: ReadExecNHook<ET, I, S>,
) -> ReadHookId {
unsafe {
let gen = get_raw_hook!(
generation_hook,
read_gen_hook_wrapper::<ET, S>,
read_gen_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(
&mut TcgHookState<5, ReadHookId>,
pc: GuestAddr,
@ -454,27 +454,27 @@ where
);
let exec1 = get_raw_hook!(
execution_hook_1,
read_0_exec_hook_wrapper::<ET, S>,
read_0_exec_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(&mut TcgHookState<5, ReadHookId>, id: u64, addr: GuestAddr)
);
let exec2 = get_raw_hook!(
execution_hook_2,
read_1_exec_hook_wrapper::<ET, S>,
read_1_exec_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(&mut TcgHookState<5, ReadHookId>, id: u64, addr: GuestAddr)
);
let exec4 = get_raw_hook!(
execution_hook_4,
read_2_exec_hook_wrapper::<ET, S>,
read_2_exec_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(&mut TcgHookState<5, ReadHookId>, id: u64, addr: GuestAddr)
);
let exec8 = get_raw_hook!(
execution_hook_8,
read_3_exec_hook_wrapper::<ET, S>,
read_3_exec_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(&mut TcgHookState<5, ReadHookId>, id: u64, addr: GuestAddr)
);
let execn = get_raw_hook!(
execution_hook_n,
read_4_exec_hook_wrapper::<ET, S>,
read_4_exec_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(
&mut TcgHookState<5, ReadHookId>,
id: u64,
@ -526,17 +526,17 @@ where
#[expect(clippy::similar_names)]
pub fn writes(
&mut self,
generation_hook: WriteGenHook<ET, S>,
execution_hook_1: WriteExecHook<ET, S>,
execution_hook_2: WriteExecHook<ET, S>,
execution_hook_4: WriteExecHook<ET, S>,
execution_hook_8: WriteExecHook<ET, S>,
execution_hook_n: WriteExecNHook<ET, S>,
generation_hook: WriteGenHook<ET, I, S>,
execution_hook_1: WriteExecHook<ET, I, S>,
execution_hook_2: WriteExecHook<ET, I, S>,
execution_hook_4: WriteExecHook<ET, I, S>,
execution_hook_8: WriteExecHook<ET, I, S>,
execution_hook_n: WriteExecNHook<ET, I, S>,
) -> WriteHookId {
unsafe {
let gen = get_raw_hook!(
generation_hook,
write_gen_hook_wrapper::<ET, S>,
write_gen_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(
&mut TcgHookState<5, WriteHookId>,
pc: GuestAddr,
@ -546,27 +546,27 @@ where
);
let exec1 = get_raw_hook!(
execution_hook_1,
write_0_exec_hook_wrapper::<ET, S>,
write_0_exec_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(&mut TcgHookState<5, WriteHookId>, id: u64, addr: GuestAddr)
);
let exec2 = get_raw_hook!(
execution_hook_2,
write_1_exec_hook_wrapper::<ET, S>,
write_1_exec_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(&mut TcgHookState<5, WriteHookId>, id: u64, addr: GuestAddr)
);
let exec4 = get_raw_hook!(
execution_hook_4,
write_2_exec_hook_wrapper::<ET, S>,
write_2_exec_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(&mut TcgHookState<5, WriteHookId>, id: u64, addr: GuestAddr)
);
let exec8 = get_raw_hook!(
execution_hook_8,
write_3_exec_hook_wrapper::<ET, S>,
write_3_exec_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(&mut TcgHookState<5, WriteHookId>, id: u64, addr: GuestAddr)
);
let execn = get_raw_hook!(
execution_hook_n,
write_4_exec_hook_wrapper::<ET, S>,
write_4_exec_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(
&mut TcgHookState<5, WriteHookId>,
id: u64,
@ -617,16 +617,16 @@ where
pub fn cmps(
&mut self,
generation_hook: CmpGenHook<ET, S>,
execution_hook_1: CmpExecHook<ET, S, u8>,
execution_hook_2: CmpExecHook<ET, S, u16>,
execution_hook_4: CmpExecHook<ET, S, u32>,
execution_hook_8: CmpExecHook<ET, S, u64>,
generation_hook: CmpGenHook<ET, I, S>,
execution_hook_1: CmpExecHook<ET, I, S, u8>,
execution_hook_2: CmpExecHook<ET, I, S, u16>,
execution_hook_4: CmpExecHook<ET, I, S, u32>,
execution_hook_8: CmpExecHook<ET, I, S, u64>,
) -> CmpHookId {
unsafe {
let gen = get_raw_hook!(
generation_hook,
cmp_gen_hook_wrapper::<ET, S>,
cmp_gen_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(
&mut TcgHookState<4, CmpHookId>,
pc: GuestAddr,
@ -635,22 +635,22 @@ where
);
let exec1 = get_raw_hook!(
execution_hook_1,
cmp_0_exec_hook_wrapper::<ET, S>,
cmp_0_exec_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(&mut TcgHookState<4, CmpHookId>, id: u64, v0: u8, v1: u8)
);
let exec2 = get_raw_hook!(
execution_hook_2,
cmp_1_exec_hook_wrapper::<ET, S>,
cmp_1_exec_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(&mut TcgHookState<4, CmpHookId>, id: u64, v0: u16, v1: u16)
);
let exec4 = get_raw_hook!(
execution_hook_4,
cmp_2_exec_hook_wrapper::<ET, S>,
cmp_2_exec_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(&mut TcgHookState<4, CmpHookId>, id: u64, v0: u32, v1: u32)
);
let exec8 = get_raw_hook!(
execution_hook_8,
cmp_3_exec_hook_wrapper::<ET, S>,
cmp_3_exec_hook_wrapper::<ET, I, S>,
unsafe extern "C" fn(&mut TcgHookState<4, CmpHookId>, id: u64, v0: u64, v1: u64)
);
@ -695,7 +695,10 @@ where
/// # Safety
/// Will dereference the hook as [`FatPtr`].
pub unsafe fn backdoor_closure(&mut self, hook: BackdoorHookClosure<ET, S>) -> BackdoorHookId {
pub unsafe fn backdoor_closure(
&mut self,
hook: BackdoorHookClosure<ET, I, S>,
) -> BackdoorHookId {
unsafe {
let fat: FatPtr = transmute(hook);
self.hook_collection
@ -713,7 +716,7 @@ where
let id = self
.qemu_hooks
.add_backdoor_hook(&mut *hook_state, closure_backdoor_hook_wrapper::<ET, S>);
.add_backdoor_hook(&mut *hook_state, closure_backdoor_hook_wrapper::<ET, I, S>);
self.hook_collection
.backdoor_hooks
@ -727,16 +730,16 @@ where
}
}
pub fn backdoor_function(&self, hook: BackdoorHookFn<ET, S>) -> BackdoorHookId {
pub fn backdoor_function(&self, hook: BackdoorHookFn<ET, I, S>) -> BackdoorHookId {
unsafe {
self.qemu_hooks
.add_backdoor_hook(transmute(hook), func_backdoor_hook_wrapper::<ET, S>)
.add_backdoor_hook(transmute(hook), func_backdoor_hook_wrapper::<ET, I, S>)
}
}
/// # Safety
/// This can call through to a potentialy unsafe `backtoor_function`
pub unsafe fn backdoor(&mut self, hook: BackdoorHook<ET, S>) -> Option<BackdoorHookId> {
pub unsafe fn backdoor(&mut self, hook: BackdoorHook<ET, I, S>) -> Option<BackdoorHookId> {
match hook {
Hook::Function(f) => Some(self.backdoor_function(f)),
Hook::Closure(c) => Some(self.backdoor_closure(c)),
@ -748,7 +751,7 @@ where
}
}
pub fn thread_creation(&mut self, hook: NewThreadHook<ET, S>) -> Option<NewThreadHookId> {
pub fn thread_creation(&mut self, hook: NewThreadHook<ET, I, S>) -> Option<NewThreadHookId> {
match hook {
Hook::Function(f) => Some(self.thread_creation_function(f)),
Hook::Closure(c) => Some(self.thread_creation_closure(c)),
@ -760,16 +763,16 @@ where
}
}
pub fn thread_creation_function(&mut self, hook: NewThreadHookFn<ET, S>) -> NewThreadHookId {
pub fn thread_creation_function(&mut self, hook: NewThreadHookFn<ET, I, S>) -> NewThreadHookId {
unsafe {
self.qemu_hooks
.add_new_thread_hook(transmute(hook), func_new_thread_hook_wrapper::<ET, S>)
.add_new_thread_hook(transmute(hook), func_new_thread_hook_wrapper::<ET, I, S>)
}
}
pub fn thread_creation_closure(
&mut self,
hook: NewThreadHookClosure<ET, S>,
hook: NewThreadHookClosure<ET, I, S>,
) -> NewThreadHookId {
unsafe {
let fat: FatPtr = transmute(hook);
@ -786,9 +789,10 @@ where
.get_unchecked_mut()
.1;
let id = self
.qemu_hooks
.add_new_thread_hook(&mut *hook_state, closure_new_thread_hook_wrapper::<ET, S>);
let id = self.qemu_hooks.add_new_thread_hook(
&mut *hook_state,
closure_new_thread_hook_wrapper::<ET, I, S>,
);
self.hook_collection
.new_thread_hooks
.last_mut()
@ -802,12 +806,13 @@ where
}
#[cfg(feature = "usermode")]
impl<ET, S> EmulatorHooks<ET, S>
impl<ET, I, S> EmulatorHooks<ET, I, S>
where
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
pub fn pre_syscalls(&mut self, hook: PreSyscallHook<ET, S>) -> Option<PreSyscallHookId> {
pub fn pre_syscalls(&mut self, hook: PreSyscallHook<ET, I, S>) -> Option<PreSyscallHookId> {
match hook {
Hook::Function(f) => Some(self.pre_syscalls_function(f)),
Hook::Closure(c) => Some(self.pre_syscalls_closure(c)),
@ -819,16 +824,19 @@ where
}
}
pub fn pre_syscalls_function(&mut self, hook: PreSyscallHookFn<ET, S>) -> PreSyscallHookId {
pub fn pre_syscalls_function(&mut self, hook: PreSyscallHookFn<ET, I, S>) -> PreSyscallHookId {
// # Safety
// Will dereference the hook as [`FatPtr`].
unsafe {
self.qemu_hooks
.add_pre_syscall_hook(transmute(hook), func_pre_syscall_hook_wrapper::<ET, S>)
.add_pre_syscall_hook(transmute(hook), func_pre_syscall_hook_wrapper::<ET, I, S>)
}
}
pub fn pre_syscalls_closure(&mut self, hook: PreSyscallHookClosure<ET, S>) -> PreSyscallHookId {
pub fn pre_syscalls_closure(
&mut self,
hook: PreSyscallHookClosure<ET, I, S>,
) -> PreSyscallHookId {
// # Safety
// Will dereference the hook as [`FatPtr`].
unsafe {
@ -847,9 +855,10 @@ where
.get_unchecked_mut()
.1;
let id = self
.qemu_hooks
.add_pre_syscall_hook(&mut *hook_state, closure_pre_syscall_hook_wrapper::<ET, S>);
let id = self.qemu_hooks.add_pre_syscall_hook(
&mut *hook_state,
closure_pre_syscall_hook_wrapper::<ET, I, S>,
);
self.hook_collection
.pre_syscall_hooks
@ -862,7 +871,7 @@ where
}
}
pub fn post_syscalls(&mut self, hook: PostSyscallHook<ET, S>) -> Option<PostSyscallHookId> {
pub fn post_syscalls(&mut self, hook: PostSyscallHook<ET, I, S>) -> Option<PostSyscallHookId> {
match hook {
Hook::Function(f) => Some(self.post_syscalls_function(f)),
Hook::Closure(c) => Some(self.post_syscalls_closure(c)),
@ -874,18 +883,21 @@ where
}
}
pub fn post_syscalls_function(&mut self, hook: PostSyscallHookFn<ET, S>) -> PostSyscallHookId {
pub fn post_syscalls_function(
&mut self,
hook: PostSyscallHookFn<ET, I, S>,
) -> PostSyscallHookId {
// # Safety
// Will dereference the hook as [`FatPtr`]. This should be ok.
unsafe {
self.qemu_hooks
.add_post_syscall_hook(transmute(hook), func_post_syscall_hook_wrapper::<ET, S>)
.add_post_syscall_hook(transmute(hook), func_post_syscall_hook_wrapper::<ET, I, S>)
}
}
pub fn post_syscalls_closure(
&mut self,
hook: PostSyscallHookClosure<ET, S>,
hook: PostSyscallHookClosure<ET, I, S>,
) -> PostSyscallHookId {
unsafe {
let fat: FatPtr = transmute(hook);
@ -904,7 +916,7 @@ where
let id = self.qemu_hooks.add_post_syscall_hook(
&mut *hooks_state,
closure_post_syscall_hook_wrapper::<ET, S>,
closure_post_syscall_hook_wrapper::<ET, I, S>,
);
self.hook_collection
.post_syscall_hooks
@ -917,20 +929,22 @@ where
}
}
pub fn crash_function(&mut self, hook: CrashHookFn<ET, S>) {
pub fn crash_function(&mut self, hook: CrashHookFn<ET, I, S>) {
// # Safety
// Will cast the valid hook to a ptr.
self.qemu_hooks.set_crash_hook(crash_hook_wrapper::<ET, S>);
self.qemu_hooks
.set_crash_hook(crash_hook_wrapper::<ET, I, S>);
self.hook_collection
.crash_hooks
.push(HookRepr::Function(hook as *const libc::c_void));
}
pub fn crash_closure(&mut self, hook: CrashHookClosure<ET, S>) {
pub fn crash_closure(&mut self, hook: CrashHookClosure<ET, I, S>) {
// # Safety
// Will cast the hook to a [`FatPtr`].
unsafe {
self.qemu_hooks.set_crash_hook(crash_hook_wrapper::<ET, S>);
self.qemu_hooks
.set_crash_hook(crash_hook_wrapper::<ET, I, S>);
self.hook_collection
.crash_hooks
.push(HookRepr::Closure(transmute(hook)));
@ -938,10 +952,7 @@ where
}
}
impl<ET, S> EmulatorModules<ET, S>
where
S: UsesInput,
{
impl<ET, I, S> EmulatorModules<ET, I, S> {
/// Get a mutable reference to `EmulatorModules` (supposedly initialized beforehand).
///
/// # Safety
@ -951,17 +962,17 @@ where
/// The user should also be consistent with the generic use (it will suppose they are the same
/// as the ones used at initialization time).
#[must_use]
pub unsafe fn emulator_modules_mut_unchecked<'a>() -> &'a mut EmulatorModules<ET, S> {
pub unsafe fn emulator_modules_mut_unchecked<'a>() -> &'a mut EmulatorModules<ET, I, S> {
#[cfg(debug_assertions)]
{
(EMULATOR_MODULES as *mut EmulatorModules<ET, S>)
(EMULATOR_MODULES as *mut EmulatorModules<ET, I, S>)
.as_mut()
.unwrap()
}
#[cfg(not(debug_assertions))]
{
&mut *(EMULATOR_MODULES as *mut EmulatorModules<ET, S>)
&mut *(EMULATOR_MODULES as *mut EmulatorModules<ET, I, S>)
}
}
@ -974,15 +985,16 @@ where
/// This version still presents some unsafeness: The user should be consistent with the
/// generic use (it will suppose they are the same as the ones used at initialization time).
#[must_use]
pub unsafe fn emulator_modules_mut<'a>() -> Option<&'a mut EmulatorModules<ET, S>> {
unsafe { (EMULATOR_MODULES as *mut EmulatorModules<ET, S>).as_mut() }
pub unsafe fn emulator_modules_mut<'a>() -> Option<&'a mut EmulatorModules<ET, I, S>> {
unsafe { (EMULATOR_MODULES as *mut EmulatorModules<ET, I, S>).as_mut() }
}
}
impl<ET, S> EmulatorModules<ET, S>
impl<ET, I, S> EmulatorModules<ET, I, S>
where
ET: Unpin,
S: UsesInput + Unpin,
I: Unpin,
S: Unpin,
{
pub fn modules_mut(&mut self) -> &mut ET {
self.modules.as_mut().get_mut()
@ -991,7 +1003,7 @@ where
pub fn instructions(
&mut self,
addr: GuestAddr,
hook: InstructionHook<ET, S>,
hook: InstructionHook<ET, I, S>,
invalidate_block: bool,
) -> Option<InstructionHookId> {
self.hooks.instructions(addr, hook, invalidate_block)
@ -1000,7 +1012,7 @@ where
pub fn instruction_function(
&mut self,
addr: GuestAddr,
hook: InstructionHookFn<ET, S>,
hook: InstructionHookFn<ET, I, S>,
invalidate_block: bool,
) -> InstructionHookId {
self.hooks
@ -1010,7 +1022,7 @@ where
pub fn instruction_closure(
&mut self,
addr: GuestAddr,
hook: InstructionHookClosure<ET, S>,
hook: InstructionHookClosure<ET, I, S>,
invalidate_block: bool,
) -> InstructionHookId {
self.hooks.instruction_closure(addr, hook, invalidate_block)
@ -1018,17 +1030,17 @@ where
pub fn edges(
&mut self,
generation_hook: EdgeGenHook<ET, S>,
execution_hook: EdgeExecHook<ET, S>,
generation_hook: EdgeGenHook<ET, I, S>,
execution_hook: EdgeExecHook<ET, I, S>,
) -> EdgeHookId {
self.hooks.edges(generation_hook, execution_hook)
}
pub fn blocks(
&mut self,
generation_hook: BlockGenHook<ET, S>,
post_generation_hook: BlockPostGenHook<ET, S>,
execution_hook: BlockExecHook<ET, S>,
generation_hook: BlockGenHook<ET, I, S>,
post_generation_hook: BlockPostGenHook<ET, I, S>,
execution_hook: BlockExecHook<ET, I, S>,
) -> BlockHookId {
self.hooks
.blocks(generation_hook, post_generation_hook, execution_hook)
@ -1036,12 +1048,12 @@ where
pub fn reads(
&mut self,
generation_hook: ReadGenHook<ET, S>,
execution_hook_1: ReadExecHook<ET, S>,
execution_hook_2: ReadExecHook<ET, S>,
execution_hook_4: ReadExecHook<ET, S>,
execution_hook_8: ReadExecHook<ET, S>,
execution_hook_n: ReadExecNHook<ET, S>,
generation_hook: ReadGenHook<ET, I, S>,
execution_hook_1: ReadExecHook<ET, I, S>,
execution_hook_2: ReadExecHook<ET, I, S>,
execution_hook_4: ReadExecHook<ET, I, S>,
execution_hook_8: ReadExecHook<ET, I, S>,
execution_hook_n: ReadExecNHook<ET, I, S>,
) -> ReadHookId {
self.hooks.reads(
generation_hook,
@ -1055,12 +1067,12 @@ where
pub fn writes(
&mut self,
generation_hook: WriteGenHook<ET, S>,
execution_hook_1: WriteExecHook<ET, S>,
execution_hook_2: WriteExecHook<ET, S>,
execution_hook_4: WriteExecHook<ET, S>,
execution_hook_8: WriteExecHook<ET, S>,
execution_hook_n: WriteExecNHook<ET, S>,
generation_hook: WriteGenHook<ET, I, S>,
execution_hook_1: WriteExecHook<ET, I, S>,
execution_hook_2: WriteExecHook<ET, I, S>,
execution_hook_4: WriteExecHook<ET, I, S>,
execution_hook_8: WriteExecHook<ET, I, S>,
execution_hook_n: WriteExecNHook<ET, I, S>,
) -> WriteHookId {
self.hooks.writes(
generation_hook,
@ -1074,11 +1086,11 @@ where
pub fn cmps(
&mut self,
generation_hook: CmpGenHook<ET, S>,
execution_hook_1: CmpExecHook<ET, S, u8>,
execution_hook_2: CmpExecHook<ET, S, u16>,
execution_hook_4: CmpExecHook<ET, S, u32>,
execution_hook_8: CmpExecHook<ET, S, u64>,
generation_hook: CmpGenHook<ET, I, S>,
execution_hook_1: CmpExecHook<ET, I, S, u8>,
execution_hook_2: CmpExecHook<ET, I, S, u16>,
execution_hook_4: CmpExecHook<ET, I, S, u32>,
execution_hook_8: CmpExecHook<ET, I, S, u64>,
) -> CmpHookId {
self.hooks.cmps(
generation_hook,
@ -1091,51 +1103,57 @@ where
/// # Safety
/// This will potentially call an unsafe backdoor hook
pub unsafe fn backdoor(&mut self, hook: BackdoorHook<ET, S>) -> Option<BackdoorHookId> {
pub unsafe fn backdoor(&mut self, hook: BackdoorHook<ET, I, S>) -> Option<BackdoorHookId> {
self.hooks.backdoor(hook)
}
pub fn backdoor_function(&mut self, hook: BackdoorHookFn<ET, S>) -> BackdoorHookId {
pub fn backdoor_function(&mut self, hook: BackdoorHookFn<ET, I, S>) -> BackdoorHookId {
self.hooks.backdoor_function(hook)
}
/// # Safety
/// Calls through to the potentially unsafe `backdoor_closure`
pub unsafe fn backdoor_closure(&mut self, hook: BackdoorHookClosure<ET, S>) -> BackdoorHookId {
pub unsafe fn backdoor_closure(
&mut self,
hook: BackdoorHookClosure<ET, I, S>,
) -> BackdoorHookId {
self.hooks.backdoor_closure(hook)
}
pub fn thread_creation(&mut self, hook: NewThreadHook<ET, S>) -> Option<NewThreadHookId> {
pub fn thread_creation(&mut self, hook: NewThreadHook<ET, I, S>) -> Option<NewThreadHookId> {
self.hooks.thread_creation(hook)
}
pub fn thread_creation_function(&mut self, hook: NewThreadHookFn<ET, S>) -> NewThreadHookId {
pub fn thread_creation_function(&mut self, hook: NewThreadHookFn<ET, I, S>) -> NewThreadHookId {
self.hooks.thread_creation_function(hook)
}
pub fn thread_creation_closure(
&mut self,
hook: NewThreadHookClosure<ET, S>,
hook: NewThreadHookClosure<ET, I, S>,
) -> NewThreadHookId {
self.hooks.thread_creation_closure(hook)
}
}
impl<ET, S> EmulatorModules<ET, S>
impl<ET, I, S> EmulatorModules<ET, I, S>
where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
/// Create a new [`EmulatorModules`]
///
/// # Safety
///
/// Only one such struct should be ever created.
pub(super) unsafe fn new(emulator_hooks: EmulatorHooks<ET, S>, modules: ET) -> Pin<Box<Self>> {
pub(super) unsafe fn new(
emulator_hooks: EmulatorHooks<ET, I, S>,
modules: ET,
) -> Pin<Box<Self>> {
let mut modules = Box::pin(Self {
modules: Box::pin(modules),
hooks: emulator_hooks,
phantom: PhantomData,
});
// re-translate blocks with hooks
@ -1173,7 +1191,7 @@ where
}
}
pub fn pre_exec_all(&mut self, qemu: Qemu, state: &mut S, input: &S::Input) {
pub fn pre_exec_all(&mut self, qemu: Qemu, state: &mut S, input: &I) {
// # Safety
// We assume that the emulator was initialized correctly
unsafe {
@ -1190,11 +1208,11 @@ where
&mut self,
qemu: Qemu,
state: &mut S,
input: &S::Input,
input: &I,
observers: &mut OT,
exit_kind: &mut ExitKind,
) where
OT: ObserversTuple<S::Input, S>,
OT: ObserversTuple<I, S>,
{
unsafe {
self.modules_mut().post_exec_all(
@ -1212,7 +1230,7 @@ where
#[must_use]
pub fn get<T>(&self) -> Option<&T>
where
T: EmulatorModule<S>,
T: EmulatorModule<I, S>,
{
self.modules.match_first_type::<T>()
}
@ -1220,38 +1238,36 @@ where
/// Get a mutable reference to the first (type) matching member of the tuple.
pub fn get_mut<T>(&mut self) -> Option<&mut T>
where
T: EmulatorModule<S>,
T: EmulatorModule<I, S>,
{
self.modules.match_first_type_mut::<T>()
}
}
impl<ET, S> EmulatorModules<ET, S>
where
S: UsesInput,
{
impl<ET, I, S> EmulatorModules<ET, I, S> {
#[must_use]
pub fn modules(&self) -> &ET {
self.modules.as_ref().get_ref()
}
pub fn hooks(&mut self) -> &EmulatorHooks<ET, S> {
pub fn hooks(&mut self) -> &EmulatorHooks<ET, I, S> {
&self.hooks
}
pub fn hooks_mut(&mut self) -> &mut EmulatorHooks<ET, S> {
pub fn hooks_mut(&mut self) -> &mut EmulatorHooks<ET, I, S> {
&mut self.hooks
}
}
/// Usermode-only high-level functions
#[cfg(feature = "usermode")]
impl<ET, S> EmulatorModules<ET, S>
impl<ET, I, S> EmulatorModules<ET, I, S>
where
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
pub fn pre_syscalls(&mut self, hook: PreSyscallHook<ET, S>) -> Option<PreSyscallHookId> {
pub fn pre_syscalls(&mut self, hook: PreSyscallHook<ET, I, S>) -> Option<PreSyscallHookId> {
self.hooks.pre_syscalls(hook)
}
@ -1260,7 +1276,7 @@ where
#[allow(clippy::type_complexity)]
pub unsafe fn pre_syscalls_function(
&mut self,
hook: PreSyscallHookFn<ET, S>,
hook: PreSyscallHookFn<ET, I, S>,
) -> PreSyscallHookId {
self.hooks.pre_syscalls_function(hook)
}
@ -1270,12 +1286,12 @@ where
#[allow(clippy::type_complexity)]
pub unsafe fn pre_syscalls_closure(
&mut self,
hook: PreSyscallHookClosure<ET, S>,
hook: PreSyscallHookClosure<ET, I, S>,
) -> PreSyscallHookId {
self.hooks.pre_syscalls_closure(hook)
}
pub fn post_syscalls(&mut self, hook: PostSyscallHook<ET, S>) -> Option<PostSyscallHookId> {
pub fn post_syscalls(&mut self, hook: PostSyscallHook<ET, I, S>) -> Option<PostSyscallHookId> {
self.hooks.post_syscalls(hook)
}
@ -1284,7 +1300,7 @@ where
#[allow(clippy::type_complexity)]
pub unsafe fn post_syscalls_function(
&mut self,
hook: PostSyscallHookFn<ET, S>,
hook: PostSyscallHookFn<ET, I, S>,
) -> PostSyscallHookId {
self.hooks.post_syscalls_function(hook)
}
@ -1292,23 +1308,23 @@ where
#[allow(clippy::type_complexity)]
pub fn post_syscalls_closure(
&mut self,
hook: PostSyscallHookClosure<ET, S>,
hook: PostSyscallHookClosure<ET, I, S>,
) -> PostSyscallHookId {
self.hooks.post_syscalls_closure(hook)
}
pub fn crash_function(&mut self, hook: CrashHookFn<ET, S>) {
pub fn crash_function(&mut self, hook: CrashHookFn<ET, I, S>) {
self.hooks.crash_function(hook);
}
/// # Safety
/// Calls through to the, potentially unsafe, registered `crash_closure`
pub unsafe fn crash_closure(&mut self, hook: CrashHookClosure<ET, S>) {
pub unsafe fn crash_closure(&mut self, hook: CrashHookClosure<ET, I, S>) {
self.hooks.crash_closure(hook);
}
}
impl<ET, S> Drop for EmulatorModules<ET, S> {
impl<ET, I, S> Drop for EmulatorModules<ET, I, S> {
fn drop(&mut self) {
// Make the global pointer null at drop time
// # Safety

View File

@ -8,7 +8,7 @@ use std::{cell::RefCell, ops::Add, pin::Pin};
use hashbrown::HashMap;
use libafl::{
executors::ExitKind,
inputs::{HasTargetBytes, UsesInput},
inputs::HasTargetBytes,
observers::ObserversTuple,
state::{HasExecutions, State},
};
@ -55,40 +55,17 @@ pub enum GuestAddrKind {
Virtual(GuestVirtAddr),
}
pub enum EmulatorExitResult<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
#[derive(Clone)]
pub enum EmulatorExitResult<C> {
QemuExit(QemuShutdownCause), // QEMU ended for some reason.
Breakpoint(Breakpoint<CM, ED, ET, S, SM>), // Breakpoint triggered. Contains the address of the trigger.
CustomInsn(CustomInsn<CM, ED, ET, S, SM>), // Synchronous backdoor: The guest triggered a backdoor and should return to LibAFL.
Breakpoint(Breakpoint<C>), // Breakpoint triggered. Contains the address of the trigger.
CustomInsn(CustomInsn<C>), // Synchronous backdoor: The guest triggered a backdoor and should return to LibAFL.
Timeout, // Timeout
}
impl<CM, ED, ET, S, SM> Clone for EmulatorExitResult<CM, ED, ET, S, SM>
impl<C> Debug for EmulatorExitResult<C>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
fn clone(&self) -> Self {
match self {
EmulatorExitResult::QemuExit(qemu_exit) => {
EmulatorExitResult::QemuExit(qemu_exit.clone())
}
EmulatorExitResult::Breakpoint(bp) => EmulatorExitResult::Breakpoint(bp.clone()),
EmulatorExitResult::CustomInsn(sync_exit) => {
EmulatorExitResult::CustomInsn(sync_exit.clone())
}
EmulatorExitResult::Timeout => EmulatorExitResult::Timeout,
}
}
}
impl<CM, ED, ET, S, SM> Debug for EmulatorExitResult<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
C: Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
@ -140,26 +117,17 @@ pub struct InputLocation {
///
/// Please check the documentation of [`EmulatorBuilder`] for more details.
#[derive(Debug)]
#[expect(clippy::type_complexity)]
pub struct Emulator<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
pub struct Emulator<C, CM, ED, ET, I, S, SM> {
snapshot_manager: SM,
modules: Pin<Box<EmulatorModules<ET, S>>>,
modules: Pin<Box<EmulatorModules<ET, I, S>>>,
command_manager: CM,
driver: ED,
breakpoints_by_addr: RefCell<HashMap<GuestAddr, Breakpoint<CM, ED, ET, S, SM>>>, // TODO: change to RC here
breakpoints_by_id: RefCell<HashMap<BreakpointId, Breakpoint<CM, ED, ET, S, SM>>>,
breakpoints_by_addr: RefCell<HashMap<GuestAddr, Breakpoint<C>>>, // TODO: change to RC here
breakpoints_by_id: RefCell<HashMap<BreakpointId, Breakpoint<C>>>,
qemu: Qemu,
}
impl<CM, ED, ET, S, SM> EmulatorDriverResult<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
impl<C> EmulatorDriverResult<C> {
#[must_use]
pub fn end_of_run(&self) -> Option<ExitKind> {
match self {
@ -243,10 +211,9 @@ impl From<CommandError> for EmulatorDriverError {
}
}
impl<CM, ED, ET, S, SM> Display for EmulatorExitResult<CM, ED, ET, S, SM>
impl<C> Display for EmulatorExitResult<C>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
C: Debug,
{
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
@ -268,16 +235,15 @@ impl From<CommandError> for EmulatorExitError {
}
}
impl<S> Emulator<NopCommandManager, NopEmulatorDriver, (), S, NopSnapshotManager>
where
S: UsesInput,
{
impl<C, I, S> Emulator<C, NopCommandManager, NopEmulatorDriver, (), I, S, NopSnapshotManager> {
#[must_use]
pub fn empty() -> EmulatorBuilder<
C,
NopCommandManager,
NopEmulatorDriver,
(),
QemuConfigBuilder,
I,
S,
NopSnapshotManager,
> {
@ -285,17 +251,19 @@ where
}
}
impl<S> Emulator<StdCommandManager<S>, StdEmulatorDriver, (), S, StdSnapshotManager>
impl<C, I, S> Emulator<C, StdCommandManager<S>, StdEmulatorDriver, (), I, S, StdSnapshotManager>
where
S: State + HasExecutions + Unpin,
S::Input: HasTargetBytes,
I: HasTargetBytes,
{
#[must_use]
pub fn builder() -> EmulatorBuilder<
C,
StdCommandManager<S>,
StdEmulatorDriver,
(),
QemuConfigBuilder,
I,
S,
StdSnapshotManager,
> {
@ -303,12 +271,8 @@ where
}
}
impl<CM, ED, ET, S, SM> Emulator<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
pub fn modules(&self) -> &EmulatorModules<ET, S> {
impl<C, CM, ED, ET, I, S, SM> Emulator<C, CM, ED, ET, I, S, SM> {
pub fn modules(&self) -> &EmulatorModules<ET, I, S> {
&self.modules
}
@ -346,22 +310,22 @@ where
}
}
impl<CM, ED, ET, S, SM> Emulator<CM, ED, ET, S, SM>
impl<C, CM, ED, ET, I, S, SM> Emulator<C, CM, ED, ET, I, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
ET: Unpin,
S: UsesInput + Unpin,
I: Unpin,
S: Unpin,
{
pub fn modules_mut(&mut self) -> &mut EmulatorModules<ET, S> {
pub fn modules_mut(&mut self) -> &mut EmulatorModules<ET, I, S> {
self.modules.as_mut().get_mut()
}
}
impl<CM, ED, ET, S, SM> Emulator<CM, ED, ET, S, SM>
impl<C, CM, ED, ET, I, S, SM> Emulator<C, CM, ED, ET, I, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
#[allow(clippy::must_use_candidate, clippy::similar_names)]
pub fn new<T>(
@ -393,7 +357,7 @@ where
// TODO: fix things there properly. The biggest issue being that it creates 2 mut ref to the module with the callback being called
unsafe {
emulator_modules.modules_mut().pre_qemu_init_all(
EmulatorModules::<ET, S>::emulator_modules_mut_unchecked(),
EmulatorModules::<ET, I, S>::emulator_modules_mut_unchecked(),
&mut qemu_params,
);
}
@ -421,7 +385,7 @@ where
/// pre-init qemu hooks should be run before calling this.
unsafe fn new_with_qemu(
qemu: Qemu,
emulator_modules: Pin<Box<EmulatorModules<ET, S>>>,
emulator_modules: Pin<Box<EmulatorModules<ET, I, S>>>,
driver: ED,
snapshot_manager: SM,
command_manager: CM,
@ -442,12 +406,14 @@ where
}
}
impl<CM, ED, ET, S, SM> Emulator<CM, ED, ET, S, SM>
impl<C, CM, ED, ET, I, S, SM> Emulator<C, CM, ED, ET, I, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
ED: EmulatorDriver<CM, ET, S, SM>,
ET: EmulatorModuleTuple<S> + Unpin,
S: UsesInput + Unpin,
C: Clone,
CM: CommandManager<C, ED, ET, I, S, SM, Commands = C>,
ED: EmulatorDriver<C, CM, ET, I, S, SM>,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
/// This function will run the emulator until the exit handler decides to stop the execution for
/// whatever reason, depending on the choosen handler.
@ -460,8 +426,8 @@ where
pub unsafe fn run(
&mut self,
state: &mut S,
input: &S::Input,
) -> Result<EmulatorDriverResult<CM, ED, ET, S, SM>, EmulatorDriverError> {
input: &I,
) -> Result<EmulatorDriverResult<C>, EmulatorDriverError> {
loop {
// Insert input if the location is already known
ED::pre_qemu_exec(self, input);
@ -485,9 +451,7 @@ where
///
/// Should, in general, be safe to call.
/// Of course, the emulated target is not contained securely and can corrupt state or interact with the operating system.
pub unsafe fn run_qemu(
&self,
) -> Result<EmulatorExitResult<CM, ED, ET, S, SM>, EmulatorExitError> {
pub unsafe fn run_qemu(&self) -> Result<EmulatorExitResult<C>, EmulatorExitError> {
match self.qemu.run() {
Ok(qemu_exit_reason) => Ok(match qemu_exit_reason {
QemuExitReason::End(qemu_shutdown_cause) => {
@ -520,34 +484,29 @@ where
}
/// Pre exec of Emulator, called before calling to user harness
pub fn pre_exec(&mut self, state: &mut S, input: &S::Input) {
pub fn pre_exec(&mut self, state: &mut S, input: &I) {
ED::pre_harness_exec(self, state, input);
}
/// Post exec of Emulator, called before calling to user harness
pub fn post_exec<OT>(
&mut self,
input: &S::Input,
input: &I,
observers: &mut OT,
state: &mut S,
exit_kind: &mut ExitKind,
) where
OT: ObserversTuple<S::Input, S>,
OT: ObserversTuple<I, S>,
{
ED::post_harness_exec(self, input, observers, state, exit_kind);
}
}
impl<CM, ED, ET, S, SM> Emulator<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
pub fn add_breakpoint(
&self,
mut bp: Breakpoint<CM, ED, ET, S, SM>,
enable: bool,
) -> BreakpointId {
impl<C, CM, ED, ET, I, S, SM> Emulator<C, CM, ED, ET, I, S, SM> {
pub fn add_breakpoint(&self, mut bp: Breakpoint<C>, enable: bool) -> BreakpointId
where
C: Clone,
{
if enable {
bp.enable(self.qemu);
}

View File

@ -1,11 +1,9 @@
use std::fmt::Debug;
use hashbrown::HashMap;
use libafl::inputs::UsesInput;
use libafl_qemu_sys::GuestPhysAddr;
use crate::{
command::CommandManager,
emu::{IsSnapshotManager, QemuSnapshotCheckResult},
DeviceSnapshotFilter, Emulator, Qemu, SnapshotId, SnapshotManagerError,
};
@ -166,11 +164,7 @@ impl IsSnapshotManager for FastSnapshotManager {
}
}
impl<CM, ED, ET, S, SM> Emulator<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
impl<C, CM, ED, ET, I, S, SM> Emulator<C, CM, ED, ET, I, S, SM> {
/// Write a value to a phsical guest address, including ROM areas.
#[allow(clippy::missing_safety_doc)]
pub unsafe fn write_phys_mem(&self, paddr: GuestPhysAddr, buf: &[u8]) {

View File

@ -1,15 +1,10 @@
use libafl::inputs::UsesInput;
use libafl_qemu_sys::{GuestAddr, MmapPerms, VerifyAccess};
use crate::{command::CommandManager, Emulator, GuestMaps, NopSnapshotManager};
use crate::{Emulator, GuestMaps, NopSnapshotManager};
pub type StdSnapshotManager = NopSnapshotManager;
impl<CM, ED, ET, S, SM> Emulator<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
impl<C, CM, ED, ET, I, S, SM> Emulator<C, CM, ED, ET, I, S, SM> {
/// This function gets the memory mappings from the emulator.
#[must_use]
pub fn mappings(&self) -> GuestMaps {

View File

@ -43,15 +43,11 @@ use crate::EmulatorModules;
use crate::Qemu;
use crate::{command::CommandManager, modules::EmulatorModuleTuple, Emulator, EmulatorDriver};
pub struct QemuExecutor<'a, CM, ED, ET, H, OT, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
ET: EmulatorModuleTuple<S>,
H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &mut S, &S::Input) -> ExitKind,
OT: ObserversTuple<S::Input, S>,
S: State,
{
inner: StatefulInProcessExecutor<'a, H, OT, S, Emulator<CM, ED, ET, S, SM>>,
type EmulatorInProcessExecutor<'a, C, CM, ED, ET, H, I, OT, S, SM> =
StatefulInProcessExecutor<'a, H, I, OT, S, Emulator<C, CM, ED, ET, I, S, SM>>;
pub struct QemuExecutor<'a, C, CM, ED, ET, H, I, OT, S, SM> {
inner: EmulatorInProcessExecutor<'a, C, CM, ED, ET, H, I, OT, S, SM>,
first_exec: bool,
}
@ -59,14 +55,15 @@ where
///
/// This should be used as a crash handler, and nothing else.
#[cfg(feature = "usermode")]
unsafe fn inproc_qemu_crash_handler<ET, S>(
unsafe fn inproc_qemu_crash_handler<ET, I, S>(
signal: Signal,
info: &mut siginfo_t,
mut context: Option<&mut ucontext_t>,
_data: &mut InProcessExecutorHandlerData,
) where
ET: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
let puc = match &mut context {
Some(v) => ptr::from_mut::<ucontext_t>(*v) as *mut c_void,
@ -74,7 +71,7 @@ unsafe fn inproc_qemu_crash_handler<ET, S>(
};
// run modules' crash callback
if let Some(emulator_modules) = EmulatorModules::<ET, S>::emulator_modules_mut() {
if let Some(emulator_modules) = EmulatorModules::<ET, I, S>::emulator_modules_mut() {
emulator_modules.modules_mut().on_crash_all();
}
@ -87,25 +84,21 @@ pub(crate) static BREAK_ON_TMOUT: AtomicBool = AtomicBool::new(false);
/// # Safety
/// Can call through the `unix_signal_handler::inproc_timeout_handler`.
/// Calling this method multiple times concurrently can lead to race conditions.
pub unsafe fn inproc_qemu_timeout_handler<E, EM, ET, OF, S, Z>(
pub unsafe fn inproc_qemu_timeout_handler<E, EM, ET, I, OF, S, Z>(
signal: Signal,
info: &mut siginfo_t,
context: Option<&mut ucontext_t>,
data: &mut InProcessExecutorHandlerData,
) where
E: HasObservers + HasInProcessHooks<S> + Executor<EM, <S::Corpus as Corpus>::Input, S, Z>,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
S: HasExecutions
+ HasSolutions
+ HasCorpus
+ Unpin
+ HasCurrentTestcase
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
<S::Corpus as Corpus>::Input: Input,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
E: HasObservers + HasInProcessHooks<I, S> + Executor<EM, I, S, Z>,
E::Observers: ObserversTuple<I, S>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
ET: EmulatorModuleTuple<S>,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions + HasSolutions + HasCorpus + Unpin + HasCurrentTestcase + UsesInput<Input = I>,
I: Input,
S::Solutions: Corpus<Input = I>,
Z: HasObjective<Objective = OF>,
{
#[cfg(feature = "systemmode")]
@ -116,6 +109,7 @@ pub unsafe fn inproc_qemu_timeout_handler<E, EM, ET, OF, S, Z>(
libafl::executors::hooks::unix::unix_signal_handler::inproc_timeout_handler::<
E,
EM,
I,
OF,
S,
Z,
@ -126,13 +120,14 @@ pub unsafe fn inproc_qemu_timeout_handler<E, EM, ET, OF, S, Z>(
#[cfg(feature = "usermode")]
{
// run modules' crash callback
if let Some(emulator_modules) = EmulatorModules::<ET, S>::emulator_modules_mut() {
if let Some(emulator_modules) = EmulatorModules::<ET, I, S>::emulator_modules_mut() {
emulator_modules.modules_mut().on_timeout_all();
}
libafl::executors::hooks::unix::unix_signal_handler::inproc_timeout_handler::<
E,
EM,
I,
OF,
S,
Z,
@ -140,13 +135,9 @@ pub unsafe fn inproc_qemu_timeout_handler<E, EM, ET, OF, S, Z>(
}
}
impl<CM, ED, ET, H, OT, S, SM> Debug for QemuExecutor<'_, CM, ED, ET, H, OT, S, SM>
impl<C, CM, ED, ET, H, I, OT, S, SM> Debug for QemuExecutor<'_, C, CM, ED, ET, H, I, OT, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
ET: EmulatorModuleTuple<S> + Debug,
H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &mut S, &S::Input) -> ExitKind,
OT: ObserversTuple<S::Input, S> + Debug,
S: State,
OT: Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("QemuExecutor")
@ -155,23 +146,17 @@ where
}
}
impl<'a, CM, ED, ET, H, OT, S, SM> QemuExecutor<'a, CM, ED, ET, H, OT, S, SM>
impl<'a, C, CM, ED, ET, H, I, OT, S, SM> QemuExecutor<'a, C, CM, ED, ET, H, I, OT, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
ET: EmulatorModuleTuple<S>,
H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &mut S, &<S::Corpus as Corpus>::Input) -> ExitKind,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
S: HasCorpus
+ Unpin
+ HasExecutions
+ HasSolutions
+ UsesInput<Input = <S::Corpus as Corpus>::Input>
+ State,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
<S::Corpus as Corpus>::Input: Input,
ET: EmulatorModuleTuple<I, S>,
H: FnMut(&mut Emulator<C, CM, ED, ET, I, S, SM>, &mut S, &I) -> ExitKind,
I: Input + Unpin,
OT: ObserversTuple<I, S>,
S: HasCorpus + Unpin + HasExecutions + HasSolutions + State<Input = I>,
S::Solutions: Corpus<Input = I>,
{
pub fn new<EM, OF, Z>(
emulator: Emulator<CM, ED, ET, S, SM>,
emulator: Emulator<C, CM, ED, ET, I, S, SM>,
harness_fn: &'a mut H,
observers: OT,
fuzzer: &mut Z,
@ -180,12 +165,13 @@ where
timeout: Duration,
) -> Result<Self, Error>
where
ED: EmulatorDriver<CM, ET, S, SM>,
C: Clone,
CM: CommandManager<C, ED, ET, I, S, SM, Commands = C>,
ED: EmulatorDriver<C, CM, ET, I, S, SM>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<EM, S::Input, OT, S>,
Z: HasObjective<Objective = OF>
+ HasScheduler<<S::Corpus as Corpus>::Input, S>
+ ExecutionProcessor<EM, <S::Corpus as Corpus>::Input, OT, S>,
OF: Feedback<EM, I, OT, S>,
Z: HasObjective<Objective = OF> + HasScheduler<I, S> + ExecutionProcessor<EM, I, OT, S>,
<S as HasCorpus>::Corpus: Corpus<Input = I>,
{
let mut inner = StatefulInProcessExecutor::with_timeout(
harness_fn, emulator, observers, fuzzer, state, event_mgr, timeout,
@ -194,13 +180,20 @@ where
#[cfg(feature = "usermode")]
{
inner.inprocess_hooks_mut().crash_handler =
inproc_qemu_crash_handler::<ET, S> as *const c_void;
inproc_qemu_crash_handler::<ET, I, S> as *const c_void;
let handler = |qemu: Qemu, _emulator_modules: &mut EmulatorModules<ET, S>, host_sig| {
let handler =
|qemu: Qemu, _emulator_modules: &mut EmulatorModules<ET, I, S>, host_sig| {
eprintln!("Crashed with signal {host_sig}");
unsafe {
libafl::executors::inprocess::generic_inproc_crash_handler::<Self, EM, OF, S, Z>(
);
libafl::executors::inprocess::generic_inproc_crash_handler::<
Self,
EM,
I,
OF,
S,
Z,
>();
}
if let Some(cpu) = qemu.current_cpu() {
eprint!("Context:\n{}", cpu.display_context());
@ -218,9 +211,10 @@ where
}
inner.inprocess_hooks_mut().timeout_handler = inproc_qemu_timeout_handler::<
StatefulInProcessExecutor<'a, H, OT, S, Emulator<CM, ED, ET, S, SM>>,
StatefulInProcessExecutor<'a, H, I, OT, S, Emulator<C, CM, ED, ET, I, S, SM>>,
EM,
ET,
I,
OF,
S,
Z,
@ -232,7 +226,7 @@ where
})
}
pub fn inner(&self) -> &StatefulInProcessExecutor<'a, H, OT, S, Emulator<CM, ED, ET, S, SM>> {
pub fn inner(&self) -> &EmulatorInProcessExecutor<'a, C, CM, ED, ET, H, I, OT, S, SM> {
&self.inner
}
@ -243,28 +237,30 @@ where
pub fn inner_mut(
&mut self,
) -> &mut StatefulInProcessExecutor<'a, H, OT, S, Emulator<CM, ED, ET, S, SM>> {
) -> &mut EmulatorInProcessExecutor<'a, C, CM, ED, ET, H, I, OT, S, SM> {
&mut self.inner
}
}
impl<CM, ED, EM, ET, H, OT, S, SM, Z> Executor<EM, <S::Corpus as Corpus>::Input, S, Z>
for QemuExecutor<'_, CM, ED, ET, H, OT, S, SM>
impl<C, CM, ED, EM, ET, H, I, OT, S, SM, Z> Executor<EM, I, S, Z>
for QemuExecutor<'_, C, CM, ED, ET, H, I, OT, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
ED: EmulatorDriver<CM, ET, S, SM>,
C: Clone,
CM: CommandManager<C, ED, ET, I, S, SM, Commands = C>,
ED: EmulatorDriver<C, CM, ET, I, S, SM>,
EM: UsesState<State = S>,
ET: EmulatorModuleTuple<S>,
H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &mut S, &<S::Corpus as Corpus>::Input) -> ExitKind,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
S: State + HasExecutions + Unpin + HasCorpus + UsesInput<Input = <S::Corpus as Corpus>::Input>,
ET: EmulatorModuleTuple<I, S>,
H: FnMut(&mut Emulator<C, CM, ED, ET, I, S, SM>, &mut S, &I) -> ExitKind,
I: Unpin,
OT: ObserversTuple<I, S>,
S: State + HasExecutions + Unpin + HasCorpus,
{
fn run_target(
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &<S::Corpus as Corpus>::Input,
input: &I,
) -> Result<ExitKind, Error> {
if self.first_exec {
self.inner.exposed_executor_state_mut().first_exec(state);
@ -288,13 +284,13 @@ where
}
}
impl<CM, ED, ET, H, OT, S, SM> HasObservers for QemuExecutor<'_, CM, ED, ET, H, OT, S, SM>
impl<C, CM, ED, ET, H, I, OT, S, SM> HasObservers
for QemuExecutor<'_, C, CM, ED, ET, H, I, OT, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
ET: EmulatorModuleTuple<S>,
H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &mut S, &<S::Corpus as Corpus>::Input) -> ExitKind,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
S: State + HasCorpus + UsesInput<Input = <S::Corpus as Corpus>::Input>,
ET: EmulatorModuleTuple<I, S>,
H: FnMut(&mut Emulator<C, CM, ED, ET, I, S, SM>, &mut S, &I) -> ExitKind,
OT: ObserversTuple<I, S>,
S: State + HasCorpus,
{
type Observers = OT;
#[inline]
@ -308,33 +304,26 @@ where
}
}
pub type QemuInProcessForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z> =
StatefulInProcessForkExecutor<'a, H, OT, S, SP, Emulator<CM, ED, ET, S, SM>, EM, Z>;
pub type QemuInProcessForkExecutor<'a, C, CM, ED, EM, ET, H, I, OT, S, SM, SP, Z> =
StatefulInProcessForkExecutor<'a, H, I, OT, S, SP, Emulator<C, CM, ED, ET, I, S, SM>, EM, Z>;
#[cfg(feature = "fork")]
pub struct QemuForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z>
where
CM: CommandManager<ED, ET, S, SM>,
ET: EmulatorModuleTuple<S>,
H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &S::Input) -> ExitKind + Sized,
OT: ObserversTuple<S::Input, S>,
S: UsesInput,
SP: ShMemProvider,
{
inner: QemuInProcessForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z>,
pub struct QemuForkExecutor<'a, C, CM, ED, EM, ET, H, I, OT, S, SM, SP, Z> {
inner: QemuInProcessForkExecutor<'a, C, CM, ED, EM, ET, H, I, OT, S, SM, SP, Z>,
}
#[cfg(feature = "fork")]
impl<CM, ED, EM, ET, H, OT, S, SM, SP, Z> Debug
for QemuForkExecutor<'_, CM, ED, EM, ET, H, OT, S, SM, SP, Z>
impl<C, CM, ED, EM, ET, H, I, OT, S, SM, SP, Z> Debug
for QemuForkExecutor<'_, C, CM, ED, EM, ET, H, I, OT, S, SM, SP, Z>
where
CM: CommandManager<ED, ET, S, SM> + Debug,
C: Debug,
CM: Debug,
EM: UsesState<State = S>,
ED: Debug,
ET: EmulatorModuleTuple<S> + Debug,
H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &S::Input) -> ExitKind + Sized,
OT: ObserversTuple<S::Input, S> + Debug,
S: UsesInput + Debug,
ET: EmulatorModuleTuple<I, S> + Debug,
OT: ObserversTuple<I, S> + Debug,
I: Debug,
S: UsesInput<Input = I> + Debug,
SM: Debug,
SP: ShMemProvider,
{
@ -347,22 +336,20 @@ where
}
#[cfg(feature = "fork")]
impl<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z>
QemuForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z>
impl<'a, C, CM, ED, EM, ET, H, I, OT, S, SM, SP, Z>
QemuForkExecutor<'a, C, CM, ED, EM, ET, H, I, OT, S, SM, SP, Z>
where
CM: CommandManager<ED, ET, S, SM>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
ET: EmulatorModuleTuple<S>,
H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &<S::Corpus as Corpus>::Input) -> ExitKind + Sized,
OT: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
S: State + HasSolutions + HasCorpus + UsesInput<Input = <S::Corpus as Corpus>::Input>,
ET: EmulatorModuleTuple<I, S>,
OT: ObserversTuple<I, S>,
S: State + HasSolutions + HasCorpus,
SP: ShMemProvider,
Z: HasObjective,
Z::Objective: Feedback<EM, <S::Corpus as Corpus>::Input, OT, S>,
Z::Objective: Feedback<EM, I, OT, S>,
{
#[expect(clippy::too_many_arguments)]
pub fn new(
emulator: Emulator<CM, ED, ET, S, SM>,
emulator: Emulator<C, CM, ED, ET, I, S, SM>,
harness_fn: &'a mut H,
observers: OT,
fuzzer: &mut Z,
@ -387,37 +374,43 @@ where
})
}
pub fn inner(&self) -> &QemuInProcessForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z> {
#[allow(clippy::type_complexity)]
pub fn inner(
&self,
) -> &QemuInProcessForkExecutor<'a, C, CM, ED, EM, ET, H, I, OT, S, SM, SP, Z> {
&self.inner
}
#[allow(clippy::type_complexity)]
pub fn inner_mut(
&mut self,
) -> &mut QemuInProcessForkExecutor<'a, CM, ED, EM, ET, H, OT, S, SM, SP, Z> {
) -> &mut QemuInProcessForkExecutor<'a, C, CM, ED, EM, ET, H, I, OT, S, SM, SP, Z> {
&mut self.inner
}
pub fn emulator(&self) -> &Emulator<CM, ED, ET, S, SM> {
pub fn emulator(&self) -> &Emulator<C, CM, ED, ET, I, S, SM> {
&self.inner.exposed_executor_state
}
pub fn emulator_mut(&mut self) -> &Emulator<CM, ED, ET, S, SM> {
pub fn emulator_mut(&mut self) -> &Emulator<C, CM, ED, ET, I, S, SM> {
&mut self.inner.exposed_executor_state
}
}
#[cfg(feature = "fork")]
impl<CM, ED, EM, ET, H, OF, OT, S, SM, SP, Z> Executor<EM, <S::Corpus as Corpus>::Input, S, Z>
for QemuForkExecutor<'_, CM, ED, EM, ET, H, OT, S, SM, SP, Z>
impl<C, CM, ED, EM, ET, H, I, OF, OT, S, SM, SP, Z> Executor<EM, I, S, Z>
for QemuForkExecutor<'_, C, CM, ED, EM, ET, H, I, OT, S, SM, SP, Z>
where
CM: CommandManager<ED, ET, S, SM>,
ED: EmulatorDriver<CM, ET, S, SM>,
C: Clone,
CM: CommandManager<C, ED, ET, I, S, SM, Commands = C>,
ED: EmulatorDriver<C, CM, ET, I, S, SM>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
ET: EmulatorModuleTuple<S>,
H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &S::Input) -> ExitKind,
OF: Feedback<EM, S::Input, OT, S>,
OT: ObserversTuple<S::Input, S> + Debug,
S: State + HasExecutions + Unpin + HasCorpus + UsesInput<Input = <S::Corpus as Corpus>::Input>,
ET: EmulatorModuleTuple<I, S>,
H: FnMut(&mut Emulator<C, CM, ED, ET, I, S, SM>, &I) -> ExitKind,
OF: Feedback<EM, I, OT, S>,
OT: ObserversTuple<I, S> + Debug,
I: Input + Unpin,
S: State + HasExecutions + Unpin + HasCorpus,
SP: ShMemProvider,
Z: HasObjective<Objective = OF>,
{
@ -426,7 +419,7 @@ where
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &<S::Corpus as Corpus>::Input,
input: &I,
) -> Result<ExitKind, Error> {
self.inner.exposed_executor_state.first_exec(state);
@ -446,13 +439,11 @@ where
}
#[cfg(feature = "fork")]
impl<CM, ED, EM, ET, H, OT, S, SM, SP, Z> UsesState
for QemuForkExecutor<'_, CM, ED, EM, ET, H, OT, S, SM, SP, Z>
impl<C, CM, ED, EM, ET, H, I, OT, S, SM, SP, Z> UsesState
for QemuForkExecutor<'_, C, CM, ED, EM, ET, H, I, OT, S, SM, SP, Z>
where
CM: CommandManager<ED, ET, S, SM>,
ET: EmulatorModuleTuple<S>,
H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &S::Input) -> ExitKind + Sized,
OT: ObserversTuple<S::Input, S>,
ET: EmulatorModuleTuple<I, S>,
OT: ObserversTuple<I, S>,
S: State,
SP: ShMemProvider,
{
@ -460,14 +451,12 @@ where
}
#[cfg(feature = "fork")]
impl<CM, ED, EM, ET, H, OT, S, SM, SP, Z> HasObservers
for QemuForkExecutor<'_, CM, ED, EM, ET, H, OT, S, SM, SP, Z>
impl<C, CM, ED, EM, ET, H, I, OT, S, SM, SP, Z> HasObservers
for QemuForkExecutor<'_, C, CM, ED, EM, ET, H, I, OT, S, SM, SP, Z>
where
CM: CommandManager<ED, ET, S, SM>,
EM: UsesState<State = S>,
ET: EmulatorModuleTuple<S>,
H: FnMut(&mut Emulator<CM, ED, ET, S, SM>, &S::Input) -> ExitKind + Sized,
OT: ObserversTuple<S::Input, S>,
ET: EmulatorModuleTuple<I, S>,
OT: ObserversTuple<I, S>,
S: State,
SP: ShMemProvider,
{

View File

@ -3,7 +3,7 @@ use core::{cell::UnsafeCell, fmt::Debug};
use capstone::prelude::*;
use libafl::{
executors::ExitKind,
inputs::{Input, UsesInput},
inputs::Input,
observers::{stacktrace::BacktraceObserver, ObserversTuple},
};
use libafl_bolts::tuples::{Handle, Handled, MatchFirstType, MatchNameRef};
@ -23,25 +23,27 @@ use crate::{
};
pub trait CallTraceCollector: 'static {
fn on_call<ET, S>(
fn on_call<ET, I, S>(
&mut self,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
state: Option<&mut S>,
pc: GuestAddr,
call_len: usize,
) where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>;
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin;
fn on_ret<ET, S>(
fn on_ret<ET, I, S>(
&mut self,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
state: Option<&mut S>,
pc: GuestAddr,
ret_addr: GuestAddr,
) where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>;
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin;
// Frowarded from the `CallTracerModule`
fn pre_exec<I>(&mut self, _qemu: Qemu, _input: &I)
@ -50,77 +52,83 @@ pub trait CallTraceCollector: 'static {
{
}
fn post_exec<OT, S>(
fn post_exec<OT, I, S>(
&mut self,
_qemu: Qemu,
_input: &S::Input,
_input: &I,
_observers: &mut OT,
_exit_kind: &mut ExitKind,
) where
OT: ObserversTuple<S::Input, S>,
S: Unpin + UsesInput,
I: Unpin,
OT: ObserversTuple<I, S>,
S: Unpin,
{
}
}
pub trait CallTraceCollectorTuple: 'static + MatchFirstType {
fn on_call_all<ET, S>(
fn on_call_all<ET, I, S>(
&mut self,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
pc: GuestAddr,
call_len: usize,
) where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>;
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin;
fn on_ret_all<ET, S>(
fn on_ret_all<ET, I, S>(
&mut self,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
_pc: GuestAddr,
ret_addr: GuestAddr,
) where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>;
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin;
fn pre_exec_all<I>(&mut self, _qemu: Qemu, input: &I)
where
I: Input;
fn post_exec_all<OT, S>(
fn post_exec_all<I, OT, S>(
&mut self,
_qemu: Qemu,
input: &S::Input,
input: &I,
_observers: &mut OT,
_exit_kind: &mut ExitKind,
) where
OT: ObserversTuple<S::Input, S>,
S: Unpin + UsesInput;
I: Unpin,
OT: ObserversTuple<I, S>,
S: Unpin;
}
impl CallTraceCollectorTuple for () {
fn on_call_all<ET, S>(
fn on_call_all<ET, I, S>(
&mut self,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
_pc: GuestAddr,
_call_len: usize,
) where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
}
fn on_ret_all<ET, S>(
fn on_ret_all<ET, I, S>(
&mut self,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
_pc: GuestAddr,
_ret_addr: GuestAddr,
) where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
}
@ -130,15 +138,16 @@ impl CallTraceCollectorTuple for () {
{
}
fn post_exec_all<OT, S>(
fn post_exec_all<I, OT, S>(
&mut self,
_emulator: Qemu,
_input: &S::Input,
_input: &I,
_observers: &mut OT,
_exit_kind: &mut ExitKind,
) where
OT: ObserversTuple<S::Input, S>,
S: Unpin + UsesInput,
I: Unpin,
OT: ObserversTuple<I, S>,
S: Unpin,
{
}
}
@ -148,15 +157,16 @@ where
Head: CallTraceCollector,
Tail: CallTraceCollectorTuple,
{
fn on_call_all<ET, S>(
fn on_call_all<ET, I, S>(
&mut self,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
mut state: Option<&mut S>,
pc: GuestAddr,
call_len: usize,
) where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
self.0.on_call(
emulator_modules,
@ -170,15 +180,16 @@ where
self.1.on_call_all(emulator_modules, state, pc, call_len);
}
fn on_ret_all<ET, S>(
fn on_ret_all<ET, I, S>(
&mut self,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
mut state: Option<&mut S>,
pc: GuestAddr,
ret_addr: GuestAddr,
) where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
self.0.on_ret(
emulator_modules,
@ -200,15 +211,16 @@ where
self.1.pre_exec_all(qemu, input);
}
fn post_exec_all<OT, S>(
fn post_exec_all<I, OT, S>(
&mut self,
qemu: Qemu,
input: &S::Input,
input: &I,
observers: &mut OT,
exit_kind: &mut ExitKind,
) where
OT: ObserversTuple<S::Input, S>,
S: Unpin + UsesInput,
I: Unpin,
OT: ObserversTuple<I, S>,
S: Unpin,
{
self.0.post_exec(qemu, input, observers, exit_kind);
self.1.post_exec_all(qemu, input, observers, exit_kind);
@ -243,14 +255,15 @@ where
self.filter.allowed(&addr)
}
fn on_ret<ET, S>(
fn on_ret<ET, I, S>(
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
state: Option<&mut S>,
pc: GuestAddr,
) where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: Input + Unpin,
S: Unpin,
{
let ret_addr: GuestAddr = qemu.read_return_address().unwrap();
@ -272,15 +285,16 @@ where
}
#[allow(clippy::needless_pass_by_value)] // no longer a problem in nightly
fn gen_blocks_calls<ET, S>(
fn gen_blocks_calls<ET, I, S>(
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
pc: GuestAddr,
) -> Option<u64>
where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: Input + Unpin,
S: Unpin,
{
if let Some(h) = emulator_modules.get_mut::<Self>() {
if !h.must_instrument(pc) {
@ -365,7 +379,7 @@ where
// TODO do not use a closure, find a more efficient way to pass call_len
let call_cb = Box::new(
move |_qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
state: Option<&mut S>,
pc| {
// eprintln!("CALL @ 0x{:#x}", pc + call_len);
@ -395,21 +409,22 @@ where
}
}
impl<S, T> EmulatorModule<S> for CallTracerModule<T>
impl<I, S, T> EmulatorModule<I, S> for CallTracerModule<T>
where
S: Unpin + UsesInput,
I: Input + Unpin,
S: Unpin,
T: CallTraceCollectorTuple + Debug,
{
type ModuleAddressFilter = StdAddressFilter;
#[cfg(feature = "systemmode")]
type ModulePageFilter = NopPageFilter;
fn post_qemu_init<ET>(&mut self, _qemu: Qemu, emulator_modules: &mut EmulatorModules<ET, S>)
fn post_qemu_init<ET>(&mut self, _qemu: Qemu, emulator_modules: &mut EmulatorModules<ET, I, S>)
where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
emulator_modules.blocks(
Hook::Function(Self::gen_blocks_calls::<ET, S>),
Hook::Function(Self::gen_blocks_calls::<ET, I, S>),
Hook::Empty,
Hook::Empty,
);
@ -418,11 +433,11 @@ where
fn pre_exec<ET>(
&mut self,
qemu: Qemu,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S,
input: &S::Input,
input: &I,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
self.collectors.as_mut().unwrap().pre_exec_all(qemu, input);
}
@ -430,14 +445,14 @@ where
fn post_exec<OT, ET>(
&mut self,
qemu: Qemu,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S,
input: &S::Input,
input: &I,
observers: &mut OT,
exit_kind: &mut ExitKind,
) where
OT: ObserversTuple<S::Input, S>,
ET: EmulatorModuleTuple<S>,
OT: ObserversTuple<I, S>,
ET: EmulatorModuleTuple<I, S>,
{
self.collectors
.as_mut()
@ -495,29 +510,31 @@ where
'a: 'static,
{
#[expect(clippy::unnecessary_cast)]
fn on_call<ET, S>(
fn on_call<ET, I, S>(
&mut self,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
pc: GuestAddr,
call_len: usize,
) where
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
self.callstack_hash ^= pc as u64 + call_len as u64;
}
#[expect(clippy::unnecessary_cast)]
fn on_ret<ET, S>(
fn on_ret<ET, I, S>(
&mut self,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
_pc: GuestAddr,
ret_addr: GuestAddr,
) where
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
self.callstack_hash ^= ret_addr as u64;
}
@ -529,15 +546,16 @@ where
self.reset();
}
fn post_exec<OT, S>(
fn post_exec<OT, I, S>(
&mut self,
_qemu: Qemu,
_input: &S::Input,
_input: &I,
observers: &mut OT,
exit_kind: &mut ExitKind,
) where
OT: ObserversTuple<S::Input, S>,
S: Unpin + UsesInput,
I: Unpin,
OT: ObserversTuple<I, S>,
S: Unpin,
{
let observer = observers
.get_mut(&self.observer_handle)
@ -591,15 +609,16 @@ impl FullBacktraceCollector {
impl CallTraceCollector for FullBacktraceCollector {
#[allow(clippy::unnecessary_cast)] // dependent on the target instruction size
fn on_call<ET, S>(
fn on_call<ET, I, S>(
&mut self,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
pc: GuestAddr,
call_len: usize,
) where
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
let callstacks_ptr = &raw mut CALLSTACKS;
// TODO handle Thumb
@ -610,15 +629,16 @@ impl CallTraceCollector for FullBacktraceCollector {
}
#[allow(clippy::unnecessary_cast)] // dependent on the target instruction size
fn on_ret<ET, S>(
fn on_ret<ET, I, S>(
&mut self,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
_pc: GuestAddr,
ret_addr: GuestAddr,
) where
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
let callstacks_ptr = &raw mut CALLSTACKS;
unsafe {

View File

@ -1,7 +1,7 @@
#[cfg(feature = "usermode")]
use capstone::{arch::BuildsCapstone, Capstone, InsnDetail};
use hashbrown::HashMap;
use libafl::{inputs::UsesInput, HasMetadata};
use libafl::HasMetadata;
use libafl_bolts::hash_64_fast;
use libafl_qemu_sys::GuestAddr;
pub use libafl_targets::{
@ -70,9 +70,10 @@ impl Default for CmpLogModule {
}
}
impl<S> EmulatorModule<S> for CmpLogModule
impl<I, S> EmulatorModule<I, S> for CmpLogModule
where
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: Unpin + HasMetadata,
{
type ModuleAddressFilter = StdAddressFilter;
#[cfg(feature = "systemmode")]
@ -81,13 +82,13 @@ where
fn first_exec<ET>(
&mut self,
_qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
emulator_modules.cmps(
Hook::Function(gen_unique_cmp_ids::<ET, S>),
Hook::Function(gen_unique_cmp_ids::<ET, I, S>),
Hook::Raw(trace_cmp1_cmplog),
Hook::Raw(trace_cmp2_cmplog),
Hook::Raw(trace_cmp4_cmplog),
@ -137,9 +138,10 @@ impl Default for CmpLogChildModule {
}
}
impl<S> EmulatorModule<S> for CmpLogChildModule
impl<I, S> EmulatorModule<I, S> for CmpLogChildModule
where
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: Unpin + HasMetadata,
{
type ModuleAddressFilter = StdAddressFilter;
#[cfg(feature = "systemmode")]
@ -150,13 +152,13 @@ where
fn first_exec<ET>(
&mut self,
_qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
emulator_modules.cmps(
Hook::Function(gen_hashed_cmp_ids::<ET, S>),
Hook::Function(gen_hashed_cmp_ids::<ET, I, S>),
Hook::Raw(trace_cmp1_cmplog),
Hook::Raw(trace_cmp2_cmplog),
Hook::Raw(trace_cmp4_cmplog),
@ -183,16 +185,17 @@ where
}
}
pub fn gen_unique_cmp_ids<ET, S>(
pub fn gen_unique_cmp_ids<ET, I, S>(
_qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
state: Option<&mut S>,
pc: GuestAddr,
_size: usize,
) -> Option<u64>
where
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput + HasMetadata,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin + HasMetadata,
{
if let Some(h) = emulator_modules.get::<CmpLogModule>() {
if !h.must_instrument(pc) {
@ -216,16 +219,17 @@ where
}
#[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly
pub fn gen_hashed_cmp_ids<ET, S>(
pub fn gen_hashed_cmp_ids<ET, I, S>(
_qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
pc: GuestAddr,
_size: usize,
) -> Option<u64>
where
S: HasMetadata + Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: HasMetadata + Unpin,
{
if let Some(h) = emulator_modules.get::<CmpLogChildModule>() {
if !h.must_instrument(pc) {
@ -311,15 +315,16 @@ impl CmpLogRoutinesModule {
}
#[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly
fn gen_blocks_calls<ET, S>(
fn gen_blocks_calls<ET, I, S>(
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
pc: GuestAddr,
) -> Option<u64>
where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
if let Some(h) = emulator_modules.get_mut::<Self>() {
if !h.must_instrument(pc) {
@ -398,9 +403,10 @@ impl CmpLogRoutinesModule {
}
#[cfg(feature = "usermode")]
impl<S> EmulatorModule<S> for CmpLogRoutinesModule
impl<I, S> EmulatorModule<I, S> for CmpLogRoutinesModule
where
S: Unpin + UsesInput,
I: Unpin,
S: Unpin,
{
type ModuleAddressFilter = StdAddressFilter;
#[cfg(feature = "systemmode")]
@ -409,13 +415,13 @@ where
fn first_exec<ET>(
&mut self,
_qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
emulator_modules.blocks(
Hook::Function(Self::gen_blocks_calls::<ET, S>),
Hook::Function(Self::gen_blocks_calls::<ET, I, S>),
Hook::Empty,
Hook::Empty,
);

View File

@ -1,7 +1,7 @@
use std::{path::PathBuf, sync::Mutex};
use hashbrown::{hash_map::Entry, HashMap};
use libafl::{executors::ExitKind, inputs::UsesInput, observers::ObserversTuple, HasMetadata};
use libafl::{executors::ExitKind, observers::ObserversTuple, HasMetadata};
use libafl_qemu_sys::{GuestAddr, GuestUsize};
use libafl_targets::drcov::{DrCovBasicBlock, DrCovWriter};
use rangemap::RangeMap;
@ -258,23 +258,24 @@ where
}
}
impl<F, S> EmulatorModule<S> for DrCovModule<F>
impl<F, I, S> EmulatorModule<I, S> for DrCovModule<F>
where
F: AddressFilter,
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: Unpin + HasMetadata,
{
type ModuleAddressFilter = F;
#[cfg(feature = "systemmode")]
type ModulePageFilter = NopPageFilter;
fn post_qemu_init<ET>(&mut self, _qemu: Qemu, emulator_modules: &mut EmulatorModules<ET, S>)
fn post_qemu_init<ET>(&mut self, _qemu: Qemu, emulator_modules: &mut EmulatorModules<ET, I, S>)
where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
emulator_modules.blocks(
Hook::Function(gen_unique_block_ids::<ET, F, S>),
Hook::Function(gen_block_lengths::<ET, F, S>),
Hook::Function(exec_trace_block::<ET, F, S>),
Hook::Function(gen_unique_block_ids::<ET, F, I, S>),
Hook::Function(gen_block_lengths::<ET, F, I, S>),
Hook::Function(exec_trace_block::<ET, F, I, S>),
);
}
@ -282,10 +283,10 @@ where
fn first_exec<ET>(
&mut self,
qemu: Qemu,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
if self.module_mapping.is_none() {
log::info!("Auto-filling module mapping for DrCov module from QEMU mapping.");
@ -315,10 +316,10 @@ where
fn first_exec<ET>(
&mut self,
_qemu: Qemu,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
assert!(
self.module_mapping.is_some(),
@ -329,14 +330,14 @@ where
fn post_exec<OT, ET>(
&mut self,
_qemu: Qemu,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_observers: &mut OT,
_exit_kind: &mut ExitKind,
) where
OT: ObserversTuple<S::Input, S>,
ET: EmulatorModuleTuple<S>,
OT: ObserversTuple<I, S>,
ET: EmulatorModuleTuple<I, S>,
{
self.write();
}
@ -368,16 +369,17 @@ where
}
}
pub fn gen_unique_block_ids<ET, F, S>(
pub fn gen_unique_block_ids<ET, F, I, S>(
_qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
state: Option<&mut S>,
pc: GuestAddr,
) -> Option<u64>
where
ET: EmulatorModuleTuple<I, S>,
F: AddressFilter,
S: Unpin + UsesInput + HasMetadata,
ET: EmulatorModuleTuple<S>,
I: Unpin,
S: Unpin + HasMetadata,
{
let drcov_module = emulator_modules.get::<DrCovModule<F>>().unwrap();
if !drcov_module.must_instrument(pc) {
@ -419,16 +421,17 @@ where
}
#[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly
pub fn gen_block_lengths<ET, F, S>(
pub fn gen_block_lengths<ET, F, I, S>(
_qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
pc: GuestAddr,
block_length: GuestUsize,
) where
ET: EmulatorModuleTuple<I, S>,
F: AddressFilter,
S: Unpin + UsesInput + HasMetadata,
ET: EmulatorModuleTuple<S>,
I: Unpin,
S: Unpin + HasMetadata,
{
let drcov_module = emulator_modules.get::<DrCovModule<F>>().unwrap();
if !drcov_module.must_instrument(pc) {
@ -443,15 +446,16 @@ pub fn gen_block_lengths<ET, F, S>(
}
#[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly
pub fn exec_trace_block<ET, F, S>(
pub fn exec_trace_block<ET, F, I, S>(
_qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
id: u64,
) where
ET: EmulatorModuleTuple<I, S>,
F: AddressFilter,
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: Unpin + HasMetadata,
{
if emulator_modules.get::<DrCovModule<F>>().unwrap().full_trace {
DRCOV_IDS.lock().unwrap().as_mut().unwrap().push(id);

View File

@ -1,4 +1,4 @@
use libafl::{inputs::UsesInput, HasMetadata};
use libafl::HasMetadata;
use super::{
helpers::{gen_hashed_edge_ids, trace_edge_hitcount_ptr, trace_edge_single_ptr},
@ -31,28 +31,30 @@ impl<AF, PF, const IS_CONST_MAP: bool, const MAP_SIZE: usize>
{
const DO_SIDE_EFFECTS: bool = false;
fn fn_hitcount<ET, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, S>)
fn fn_hitcount<ET, I, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, I, S>)
where
AF: AddressFilter,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
PF: PageFilter,
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: HasMetadata + Unpin,
{
emulator_modules.edges(
Hook::Function(gen_hashed_edge_ids::<AF, ET, PF, S, Self, IS_CONST_MAP, MAP_SIZE>),
Hook::Function(gen_hashed_edge_ids::<AF, ET, PF, I, S, Self, IS_CONST_MAP, MAP_SIZE>),
Hook::Raw(trace_edge_hitcount_ptr),
);
}
fn fn_no_hitcount<ET, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, S>)
fn fn_no_hitcount<ET, I, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, I, S>)
where
AF: AddressFilter,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
PF: PageFilter,
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: HasMetadata + Unpin,
{
emulator_modules.edges(
Hook::Function(gen_hashed_edge_ids::<AF, ET, PF, S, Self, IS_CONST_MAP, MAP_SIZE>),
Hook::Function(gen_hashed_edge_ids::<AF, ET, PF, I, S, Self, IS_CONST_MAP, MAP_SIZE>),
Hook::Raw(trace_edge_single_ptr),
);
}

View File

@ -1,4 +1,4 @@
use libafl::{inputs::UsesInput, HasMetadata};
use libafl::HasMetadata;
use super::{
helpers::{
@ -34,15 +34,16 @@ impl<AF, PF, const IS_CONST_MAP: bool, const MAP_SIZE: usize>
{
const DO_SIDE_EFFECTS: bool = false;
fn jit_hitcount<ET, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, S>)
fn jit_hitcount<ET, I, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, I, S>)
where
AF: AddressFilter,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
PF: PageFilter,
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: HasMetadata + Unpin,
{
let hook_id = emulator_modules.blocks(
Hook::Function(gen_hashed_block_ids::<AF, ET, PF, S, Self, IS_CONST_MAP, MAP_SIZE>),
Hook::Function(gen_hashed_block_ids::<AF, ET, PF, I, S, Self, IS_CONST_MAP, MAP_SIZE>),
Hook::Empty,
Hook::Empty,
);
@ -55,15 +56,16 @@ impl<AF, PF, const IS_CONST_MAP: bool, const MAP_SIZE: usize>
}
}
fn jit_no_hitcount<ET, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, S>)
fn jit_no_hitcount<ET, I, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, I, S>)
where
AF: AddressFilter,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
PF: PageFilter,
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: HasMetadata + Unpin,
{
let hook_id = emulator_modules.blocks(
Hook::Function(gen_hashed_block_ids::<AF, ET, PF, S, Self, IS_CONST_MAP, MAP_SIZE>),
Hook::Function(gen_hashed_block_ids::<AF, ET, PF, I, S, Self, IS_CONST_MAP, MAP_SIZE>),
Hook::Empty,
Hook::Empty,
);
@ -76,29 +78,31 @@ impl<AF, PF, const IS_CONST_MAP: bool, const MAP_SIZE: usize>
}
}
fn fn_hitcount<ET, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, S>)
fn fn_hitcount<ET, I, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, I, S>)
where
AF: AddressFilter,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
PF: PageFilter,
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: HasMetadata + Unpin,
{
emulator_modules.blocks(
Hook::Function(gen_hashed_block_ids::<AF, ET, PF, S, Self, IS_CONST_MAP, MAP_SIZE>),
Hook::Function(gen_hashed_block_ids::<AF, ET, PF, I, S, Self, IS_CONST_MAP, MAP_SIZE>),
Hook::Empty,
Hook::Raw(trace_block_transition_hitcount),
);
}
fn fn_no_hitcount<ET, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, S>)
fn fn_no_hitcount<ET, I, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, I, S>)
where
AF: AddressFilter,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
PF: PageFilter,
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: HasMetadata + Unpin,
{
emulator_modules.blocks(
Hook::Function(gen_hashed_block_ids::<AF, ET, PF, S, Self, IS_CONST_MAP, MAP_SIZE>),
Hook::Function(gen_hashed_block_ids::<AF, ET, PF, I, S, Self, IS_CONST_MAP, MAP_SIZE>),
Hook::Empty,
Hook::Raw(trace_block_transition_single),
);

View File

@ -1,4 +1,4 @@
use libafl::{inputs::UsesInput, HasMetadata};
use libafl::HasMetadata;
use super::{
helpers::{gen_unique_edge_ids, trace_edge_hitcount, trace_edge_single},
@ -30,15 +30,16 @@ pub type StdEdgeCoverageFullModuleBuilder = EdgeCoverageModuleBuilder<
impl<AF, PF, const IS_CONST_MAP: bool, const MAP_SIZE: usize>
EdgeCoverageVariant<AF, PF, IS_CONST_MAP, MAP_SIZE> for EdgeCoverageFullVariant
{
fn jit_hitcount<ET, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, S>)
fn jit_hitcount<ET, I, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, I, S>)
where
AF: AddressFilter,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
PF: PageFilter,
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: HasMetadata + Unpin,
{
let hook_id = emulator_modules.edges(
Hook::Function(gen_unique_edge_ids::<AF, ET, PF, S, Self, IS_CONST_MAP, MAP_SIZE>),
Hook::Function(gen_unique_edge_ids::<AF, ET, PF, I, S, Self, IS_CONST_MAP, MAP_SIZE>),
Hook::Empty,
);
unsafe {
@ -49,15 +50,16 @@ impl<AF, PF, const IS_CONST_MAP: bool, const MAP_SIZE: usize>
}
}
fn jit_no_hitcount<ET, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, S>)
fn jit_no_hitcount<ET, I, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, I, S>)
where
AF: AddressFilter,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
PF: PageFilter,
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: HasMetadata + Unpin,
{
let hook_id = emulator_modules.edges(
Hook::Function(gen_unique_edge_ids::<AF, ET, PF, S, Self, IS_CONST_MAP, MAP_SIZE>),
Hook::Function(gen_unique_edge_ids::<AF, ET, PF, I, S, Self, IS_CONST_MAP, MAP_SIZE>),
Hook::Empty,
);
unsafe {
@ -68,28 +70,30 @@ impl<AF, PF, const IS_CONST_MAP: bool, const MAP_SIZE: usize>
}
}
fn fn_hitcount<ET, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, S>)
fn fn_hitcount<ET, I, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, I, S>)
where
AF: AddressFilter,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
PF: PageFilter,
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: HasMetadata + Unpin,
{
emulator_modules.edges(
Hook::Function(gen_unique_edge_ids::<AF, ET, PF, S, Self, IS_CONST_MAP, MAP_SIZE>),
Hook::Function(gen_unique_edge_ids::<AF, ET, PF, I, S, Self, IS_CONST_MAP, MAP_SIZE>),
Hook::Raw(trace_edge_hitcount),
);
}
fn fn_no_hitcount<ET, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, S>)
fn fn_no_hitcount<ET, I, S>(&mut self, emulator_modules: &mut EmulatorModules<ET, I, S>)
where
AF: AddressFilter,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
PF: PageFilter,
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: HasMetadata + Unpin,
{
emulator_modules.edges(
Hook::Function(gen_unique_edge_ids::<AF, ET, PF, S, Self, IS_CONST_MAP, MAP_SIZE>),
Hook::Function(gen_unique_edge_ids::<AF, ET, PF, I, S, Self, IS_CONST_MAP, MAP_SIZE>),
Hook::Raw(trace_edge_single),
);
}

View File

@ -51,7 +51,7 @@ mod generators {
use std::{cmp::max, ptr};
use hashbrown::hash_map::Entry;
use libafl::{inputs::UsesInput, HasMetadata};
use libafl::HasMetadata;
use libafl_bolts::hash_64_fast;
use libafl_qemu_sys::GuestAddr;
@ -79,18 +79,28 @@ mod generators {
}
#[allow(unused_variables)]
pub fn gen_unique_edge_ids<AF, ET, PF, S, V, const IS_CONST_MAP: bool, const MAP_SIZE: usize>(
pub fn gen_unique_edge_ids<
AF,
ET,
PF,
I,
S,
V,
const IS_CONST_MAP: bool,
const MAP_SIZE: usize,
>(
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
state: Option<&mut S>,
src: GuestAddr,
dest: GuestAddr,
) -> Option<u64>
where
AF: AddressFilter,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
PF: PageFilter,
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: HasMetadata + Unpin,
V: EdgeCoverageVariant<AF, PF, IS_CONST_MAP, MAP_SIZE>,
{
if let Some(module) =
@ -157,18 +167,28 @@ mod generators {
#[allow(unused_variables)]
#[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly
pub fn gen_hashed_edge_ids<AF, ET, PF, S, V, const IS_CONST_MAP: bool, const MAP_SIZE: usize>(
pub fn gen_hashed_edge_ids<
AF,
ET,
PF,
I,
S,
V,
const IS_CONST_MAP: bool,
const MAP_SIZE: usize,
>(
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
src: GuestAddr,
dest: GuestAddr,
) -> Option<u64>
where
AF: AddressFilter,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
PF: PageFilter,
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: HasMetadata + Unpin,
V: EdgeCoverageVariant<AF, PF, IS_CONST_MAP, MAP_SIZE>,
{
if let Some(module) =
@ -211,17 +231,27 @@ mod generators {
#[expect(clippy::unnecessary_cast)]
#[allow(unused_variables)]
#[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly
pub fn gen_hashed_block_ids<AF, ET, PF, S, V, const IS_CONST_MAP: bool, const MAP_SIZE: usize>(
pub fn gen_hashed_block_ids<
AF,
ET,
PF,
I,
S,
V,
const IS_CONST_MAP: bool,
const MAP_SIZE: usize,
>(
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
pc: GuestAddr,
) -> Option<u64>
where
AF: AddressFilter,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
PF: PageFilter,
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: HasMetadata + Unpin,
V: EdgeCoverageVariant<AF, PF, IS_CONST_MAP, MAP_SIZE>,
{
// first check if we should filter

View File

@ -1,6 +1,6 @@
use std::fmt::Debug;
use libafl::{inputs::UsesInput, observers::VarLenMapObserver, HasMetadata};
use libafl::{observers::VarLenMapObserver, HasMetadata};
use libafl_bolts::Error;
use libafl_qemu_sys::GuestAddr;
#[cfg(feature = "systemmode")]
@ -49,42 +49,46 @@ trait EdgeCoverageVariant<AF, PF, const IS_CONST_MAP: bool, const MAP_SIZE: usiz
{
const DO_SIDE_EFFECTS: bool = true;
fn jit_hitcount<ET, S>(&mut self, _emulator_modules: &mut EmulatorModules<ET, S>)
fn jit_hitcount<ET, I, S>(&mut self, _emulator_modules: &mut EmulatorModules<ET, I, S>)
where
AF: AddressFilter,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
PF: PageFilter,
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: HasMetadata + Unpin,
{
panic!("JIT hitcount is not supported.")
}
fn jit_no_hitcount<ET, S>(&mut self, _emulator_modules: &mut EmulatorModules<ET, S>)
fn jit_no_hitcount<ET, I, S>(&mut self, _emulator_modules: &mut EmulatorModules<ET, I, S>)
where
AF: AddressFilter,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
PF: PageFilter,
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: HasMetadata + Unpin,
{
panic!("JIT no hitcount is not supported.")
}
fn fn_hitcount<ET, S>(&mut self, _emulator_modules: &mut EmulatorModules<ET, S>)
fn fn_hitcount<ET, I, S>(&mut self, _emulator_modules: &mut EmulatorModules<ET, I, S>)
where
AF: AddressFilter,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
PF: PageFilter,
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: HasMetadata + Unpin,
{
panic!("Func hitcount is not supported.")
}
fn fn_no_hitcount<ET, S>(&mut self, _emulator_modules: &mut EmulatorModules<ET, S>)
fn fn_no_hitcount<ET, I, S>(&mut self, _emulator_modules: &mut EmulatorModules<ET, I, S>)
where
AF: AddressFilter,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
PF: PageFilter,
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: HasMetadata + Unpin,
{
panic!("Func no hitcount is not supported.")
}
@ -314,12 +318,13 @@ where
}
}
impl<S, AF, PF, V, const IS_CONST_MAP: bool, const MAP_SIZE: usize> EmulatorModule<S>
impl<I, S, AF, PF, V, const IS_CONST_MAP: bool, const MAP_SIZE: usize> EmulatorModule<I, S>
for EdgeCoverageModule<AF, PF, V, IS_CONST_MAP, MAP_SIZE>
where
AF: AddressFilter + 'static,
PF: PageFilter + 'static,
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: Unpin + HasMetadata,
V: EdgeCoverageVariant<AF, PF, IS_CONST_MAP, MAP_SIZE> + 'static,
{
type ModuleAddressFilter = AF;
@ -331,10 +336,10 @@ where
fn first_exec<ET>(
&mut self,
_qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
if self.use_hitcounts {
if self.use_jit {

View File

@ -1,6 +1,6 @@
use core::{fmt::Debug, ops::Range};
use libafl::{executors::ExitKind, inputs::UsesInput, observers::ObserversTuple};
use libafl::{executors::ExitKind, observers::ObserversTuple};
use libafl_bolts::tuples::{MatchFirstType, SplitBorrowExtractFirstType};
use libafl_qemu_sys::GuestAddr;
#[cfg(feature = "systemmode")]
@ -50,10 +50,7 @@ pub mod utils;
/// A module for `libafl_qemu`.
// TODO remove 'static when specialization will be stable
pub trait EmulatorModule<S>: 'static + Debug
where
S: UsesInput,
{
pub trait EmulatorModule<I, S>: 'static + Debug {
type ModuleAddressFilter: AddressFilter;
#[cfg(feature = "systemmode")]
@ -69,19 +66,19 @@ where
/// Thus, the module can modify options for QEMU just before it gets initialized.
fn pre_qemu_init<ET>(
&mut self,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_qemu_params: &mut QemuParams,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
}
/// Hook run **after** QEMU is initialized.
/// This is always run when Emulator gets initialized, in any case.
/// Install here hooks that should be alive for the whole execution of the VM, after QEMU gets initialized.
fn post_qemu_init<ET>(&mut self, _qemu: Qemu, _emulator_modules: &mut EmulatorModules<ET, S>)
fn post_qemu_init<ET>(&mut self, _qemu: Qemu, _emulator_modules: &mut EmulatorModules<ET, I, S>)
where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
}
@ -92,10 +89,10 @@ where
fn first_exec<ET>(
&mut self,
_qemu: Qemu,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
}
@ -104,11 +101,11 @@ where
fn pre_exec<ET>(
&mut self,
_qemu: Qemu,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S,
_input: &S::Input,
_input: &I,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
}
@ -116,14 +113,14 @@ where
fn post_exec<OT, ET>(
&mut self,
_qemu: Qemu,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_observers: &mut OT,
_exit_kind: &mut ExitKind,
) where
OT: ObserversTuple<S::Input, S>,
ET: EmulatorModuleTuple<S>,
OT: ObserversTuple<I, S>,
ET: EmulatorModuleTuple<I, S>,
{
}
@ -157,52 +154,53 @@ where
}
}
pub trait EmulatorModuleTuple<S>:
pub trait EmulatorModuleTuple<I, S>:
MatchFirstType + for<'a> SplitBorrowExtractFirstType<'a> + Unpin
where
S: UsesInput,
{
const HOOKS_DO_SIDE_EFFECTS: bool;
fn pre_qemu_init_all<ET>(
&mut self,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
qemu_params: &mut QemuParams,
) where
ET: EmulatorModuleTuple<S>;
ET: EmulatorModuleTuple<I, S>;
fn post_qemu_init_all<ET>(&mut self, qemu: Qemu, emulator_modules: &mut EmulatorModules<ET, S>)
where
ET: EmulatorModuleTuple<S>;
fn post_qemu_init_all<ET>(
&mut self,
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, I, S>,
) where
ET: EmulatorModuleTuple<I, S>;
fn first_exec_all<ET>(
&mut self,
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
state: &mut S,
) where
ET: EmulatorModuleTuple<S>;
ET: EmulatorModuleTuple<I, S>;
fn pre_exec_all<ET>(
&mut self,
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
state: &mut S,
input: &S::Input,
input: &I,
) where
ET: EmulatorModuleTuple<S>;
ET: EmulatorModuleTuple<I, S>;
fn post_exec_all<OT, ET>(
&mut self,
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
state: &mut S,
input: &S::Input,
input: &I,
observers: &mut OT,
exit_kind: &mut ExitKind,
) where
OT: ObserversTuple<S::Input, S>,
ET: EmulatorModuleTuple<S>;
OT: ObserversTuple<I, S>,
ET: EmulatorModuleTuple<I, S>;
/// # Safety
///
@ -220,62 +218,62 @@ where
fn allow_page_id_all(&mut self, page_id: GuestPhysAddr);
}
impl<S> EmulatorModuleTuple<S> for ()
impl<I, S> EmulatorModuleTuple<I, S> for ()
where
S: UsesInput + Unpin,
S: Unpin,
{
const HOOKS_DO_SIDE_EFFECTS: bool = false;
fn pre_qemu_init_all<ET>(
&mut self,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_qemu_params: &mut QemuParams,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
}
fn post_qemu_init_all<ET>(
&mut self,
_qemu: Qemu,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
}
fn first_exec_all<ET>(
&mut self,
_qemu: Qemu,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
}
fn pre_exec_all<ET>(
&mut self,
_qemu: Qemu,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S,
_input: &S::Input,
_input: &I,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
}
fn post_exec_all<OT, ET>(
&mut self,
_qemu: Qemu,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_observers: &mut OT,
_exit_kind: &mut ExitKind,
) where
OT: ObserversTuple<S::Input, S>,
ET: EmulatorModuleTuple<S>,
OT: ObserversTuple<I, S>,
ET: EmulatorModuleTuple<I, S>,
{
}
@ -289,28 +287,31 @@ where
fn allow_page_id_all(&mut self, _page_id: GuestPhysAddr) {}
}
impl<Head, Tail, S> EmulatorModuleTuple<S> for (Head, Tail)
impl<Head, Tail, I, S> EmulatorModuleTuple<I, S> for (Head, Tail)
where
Head: EmulatorModule<S> + Unpin,
Tail: EmulatorModuleTuple<S>,
S: UsesInput + Unpin,
Head: EmulatorModule<I, S> + Unpin,
Tail: EmulatorModuleTuple<I, S>,
S: Unpin,
{
const HOOKS_DO_SIDE_EFFECTS: bool = Head::HOOKS_DO_SIDE_EFFECTS || Tail::HOOKS_DO_SIDE_EFFECTS;
fn pre_qemu_init_all<ET>(
&mut self,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
qemu_params: &mut QemuParams,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
self.0.pre_qemu_init(emulator_modules, qemu_params);
self.1.pre_qemu_init_all(emulator_modules, qemu_params);
}
fn post_qemu_init_all<ET>(&mut self, qemu: Qemu, emulator_modules: &mut EmulatorModules<ET, S>)
where
ET: EmulatorModuleTuple<S>,
fn post_qemu_init_all<ET>(
&mut self,
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, I, S>,
) where
ET: EmulatorModuleTuple<I, S>,
{
self.0.post_qemu_init(qemu, emulator_modules);
self.1.post_qemu_init_all(qemu, emulator_modules);
@ -319,10 +320,10 @@ where
fn first_exec_all<ET>(
&mut self,
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
state: &mut S,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
self.0.first_exec(qemu, emulator_modules, state);
self.1.first_exec_all(qemu, emulator_modules, state);
@ -331,11 +332,11 @@ where
fn pre_exec_all<ET>(
&mut self,
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
state: &mut S,
input: &S::Input,
input: &I,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
self.0.pre_exec(qemu, emulator_modules, state, input);
self.1.pre_exec_all(qemu, emulator_modules, state, input);
@ -344,14 +345,14 @@ where
fn post_exec_all<OT, ET>(
&mut self,
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
state: &mut S,
input: &S::Input,
input: &I,
observers: &mut OT,
exit_kind: &mut ExitKind,
) where
OT: ObserversTuple<S::Input, S>,
ET: EmulatorModuleTuple<S>,
OT: ObserversTuple<I, S>,
ET: EmulatorModuleTuple<I, S>,
{
self.0
.post_exec(qemu, emulator_modules, state, input, observers, exit_kind);

View File

@ -3,7 +3,7 @@
use std::{borrow::Cow, env, fs, path::PathBuf, sync::Mutex};
use hashbrown::{HashMap, HashSet};
use libafl::{executors::ExitKind, inputs::UsesInput, observers::ObserversTuple};
use libafl::{executors::ExitKind, observers::ObserversTuple};
use libc::{
c_void, MAP_ANON, MAP_FAILED, MAP_FIXED, MAP_NORESERVE, MAP_PRIVATE, PROT_READ, PROT_WRITE,
};
@ -810,19 +810,20 @@ impl AsanModule {
}
}
impl<S> EmulatorModule<S> for AsanModule
impl<I, S> EmulatorModule<I, S> for AsanModule
where
S: Unpin + UsesInput,
I: Unpin,
S: Unpin,
{
type ModuleAddressFilter = StdAddressFilter;
const HOOKS_DO_SIDE_EFFECTS: bool = false;
fn pre_qemu_init<ET>(
&mut self,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
qemu_params: &mut QemuParams,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
let mut args: Vec<String> = qemu_params.to_cli();
@ -874,52 +875,52 @@ where
*qemu_params = QemuParams::Cli(args);
}
fn post_qemu_init<ET>(&mut self, _qemu: Qemu, emulator_modules: &mut EmulatorModules<ET, S>)
fn post_qemu_init<ET>(&mut self, _qemu: Qemu, emulator_modules: &mut EmulatorModules<ET, I, S>)
where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
emulator_modules.pre_syscalls(Hook::Function(qasan_fake_syscall::<ET, S>));
emulator_modules.pre_syscalls(Hook::Function(qasan_fake_syscall::<ET, I, S>));
if self.rt.error_callback.is_some() {
emulator_modules.crash_function(oncrash_asan::<ET, S>);
emulator_modules.crash_function(oncrash_asan::<ET, I, S>);
}
}
fn first_exec<ET>(
&mut self,
_qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
emulator_modules.reads(
Hook::Function(gen_readwrite_asan::<ET, S>),
Hook::Function(trace_read_asan::<ET, S, 1>),
Hook::Function(trace_read_asan::<ET, S, 2>),
Hook::Function(trace_read_asan::<ET, S, 4>),
Hook::Function(trace_read_asan::<ET, S, 8>),
Hook::Function(trace_read_n_asan::<ET, S>),
Hook::Function(gen_readwrite_asan::<ET, I, S>),
Hook::Function(trace_read_asan::<ET, I, S, 1>),
Hook::Function(trace_read_asan::<ET, I, S, 2>),
Hook::Function(trace_read_asan::<ET, I, S, 4>),
Hook::Function(trace_read_asan::<ET, I, S, 8>),
Hook::Function(trace_read_n_asan::<ET, I, S>),
);
if emulator_modules.get::<SnapshotModule>().is_none() {
emulator_modules.writes(
Hook::Function(gen_readwrite_asan::<ET, S>),
Hook::Function(trace_write_asan::<ET, S, 1>),
Hook::Function(trace_write_asan::<ET, S, 2>),
Hook::Function(trace_write_asan::<ET, S, 4>),
Hook::Function(trace_write_asan::<ET, S, 8>),
Hook::Function(trace_write_n_asan::<ET, S>),
Hook::Function(gen_readwrite_asan::<ET, I, S>),
Hook::Function(trace_write_asan::<ET, I, S, 1>),
Hook::Function(trace_write_asan::<ET, I, S, 2>),
Hook::Function(trace_write_asan::<ET, I, S, 4>),
Hook::Function(trace_write_asan::<ET, I, S, 8>),
Hook::Function(trace_write_n_asan::<ET, I, S>),
);
} else {
// track writes for both modules as opt
emulator_modules.writes(
Hook::Function(gen_write_asan_snapshot::<ET, S>),
Hook::Function(trace_write_asan_snapshot::<ET, S, 1>),
Hook::Function(trace_write_asan_snapshot::<ET, S, 2>),
Hook::Function(trace_write_asan_snapshot::<ET, S, 4>),
Hook::Function(trace_write_asan_snapshot::<ET, S, 8>),
Hook::Function(trace_write_n_asan_snapshot::<ET, S>),
Hook::Function(gen_write_asan_snapshot::<ET, I, S>),
Hook::Function(trace_write_asan_snapshot::<ET, I, S, 1>),
Hook::Function(trace_write_asan_snapshot::<ET, I, S, 2>),
Hook::Function(trace_write_asan_snapshot::<ET, I, S, 4>),
Hook::Function(trace_write_asan_snapshot::<ET, I, S, 8>),
Hook::Function(trace_write_n_asan_snapshot::<ET, I, S>),
);
}
}
@ -927,11 +928,11 @@ where
fn pre_exec<ET>(
&mut self,
qemu: Qemu,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S,
_input: &S::Input,
_input: &I,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
if self.empty {
self.rt.snapshot(qemu);
@ -942,14 +943,14 @@ where
fn post_exec<OT, ET>(
&mut self,
qemu: Qemu,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S,
_input: &S::Input,
_input: &I,
_observers: &mut OT,
exit_kind: &mut ExitKind,
) where
OT: ObserversTuple<S::Input, S>,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
OT: ObserversTuple<I, S>,
{
if self.reset(qemu) == AsanRollback::HasLeaks {
*exit_kind = ExitKind::Crash;
@ -965,30 +966,32 @@ where
}
}
pub fn oncrash_asan<ET, S>(
pub fn oncrash_asan<ET, I, S>(
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
target_sig: i32,
) where
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
let h = emulator_modules.get_mut::<AsanModule>().unwrap();
let pc: GuestAddr = qemu.read_reg(Regs::Pc).unwrap();
h.rt.report(qemu, pc, AsanError::Signal(target_sig));
}
pub fn gen_readwrite_asan<ET, S>(
pub fn gen_readwrite_asan<ET, I, S>(
_qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
pc: GuestAddr,
_addr: *mut TCGTemp,
_info: MemAccessInfo,
) -> Option<u64>
where
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
let h = emulator_modules.get_mut::<AsanModule>().unwrap();
if h.must_instrument(pc) {
@ -998,75 +1001,80 @@ where
}
}
pub fn trace_read_asan<ET, S, const N: usize>(
pub fn trace_read_asan<ET, I, S, const N: usize>(
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
id: u64,
addr: GuestAddr,
) where
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
let h = emulator_modules.get_mut::<AsanModule>().unwrap();
h.read::<N>(qemu, id as GuestAddr, addr);
}
pub fn trace_read_n_asan<ET, S>(
pub fn trace_read_n_asan<ET, I, S>(
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
id: u64,
addr: GuestAddr,
size: usize,
) where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
let h = emulator_modules.get_mut::<AsanModule>().unwrap();
h.read_n(qemu, id as GuestAddr, addr, size);
}
pub fn trace_write_asan<ET, S, const N: usize>(
pub fn trace_write_asan<ET, I, S, const N: usize>(
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
id: u64,
addr: GuestAddr,
) where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
let h = emulator_modules.get_mut::<AsanModule>().unwrap();
h.write::<N>(qemu, id as GuestAddr, addr);
}
pub fn trace_write_n_asan<ET, S>(
pub fn trace_write_n_asan<ET, I, S>(
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
id: u64,
addr: GuestAddr,
size: usize,
) where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
let h = emulator_modules.get_mut::<AsanModule>().unwrap();
h.read_n(qemu, id as GuestAddr, addr, size);
}
pub fn gen_write_asan_snapshot<ET, S>(
pub fn gen_write_asan_snapshot<ET, I, S>(
_qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
pc: GuestAddr,
_addr: *mut TCGTemp,
_info: MemAccessInfo,
) -> Option<u64>
where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
let h = emulator_modules.get_mut::<AsanModule>().unwrap();
if h.must_instrument(pc) {
@ -1076,15 +1084,16 @@ where
}
}
pub fn trace_write_asan_snapshot<ET, S, const N: usize>(
pub fn trace_write_asan_snapshot<ET, I, S, const N: usize>(
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
id: u64,
addr: GuestAddr,
) where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
if id != 0 {
let h = emulator_modules.get_mut::<AsanModule>().unwrap();
@ -1094,16 +1103,17 @@ pub fn trace_write_asan_snapshot<ET, S, const N: usize>(
h.access(addr, N);
}
pub fn trace_write_n_asan_snapshot<ET, S>(
pub fn trace_write_n_asan_snapshot<ET, I, S>(
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
id: u64,
addr: GuestAddr,
size: usize,
) where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
if id != 0 {
let h = emulator_modules.get_mut::<AsanModule>().unwrap();
@ -1114,9 +1124,9 @@ pub fn trace_write_n_asan_snapshot<ET, S>(
}
#[expect(clippy::too_many_arguments)]
pub fn qasan_fake_syscall<ET, S>(
pub fn qasan_fake_syscall<ET, I, S>(
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
sys_num: i32,
a0: GuestAddr,
@ -1129,8 +1139,9 @@ pub fn qasan_fake_syscall<ET, S>(
_a7: GuestAddr,
) -> SyscallHookResult
where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
if sys_num == QASAN_FAKESYS_NR {
let h = emulator_modules.get_mut::<AsanModule>().unwrap();

View File

@ -7,7 +7,6 @@ use std::{
path::PathBuf,
};
use libafl::inputs::UsesInput;
use libafl_qemu_sys::{GuestAddr, MapInfo};
#[cfg(not(feature = "clippy"))]
@ -107,18 +106,19 @@ where
}
#[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly
fn gen_readwrite_guest_asan<ET, F, S>(
fn gen_readwrite_guest_asan<ET, F, I, S>(
_qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
pc: GuestAddr,
addr: *mut TCGTemp,
info: MemAccessInfo,
) -> Option<u64>
where
ET: EmulatorModuleTuple<I, S>,
F: AddressFilter,
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
I: Unpin,
S: Unpin,
{
let h = emulator_modules.get_mut::<AsanGuestModule<F>>().unwrap();
if !h.must_instrument(pc) {
@ -154,47 +154,50 @@ where
unsafe fn libafl_tcg_gen_asan(addr: *mut TCGTemp, size: usize) {}
#[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly
fn guest_trace_error_asan<ET, S>(
fn guest_trace_error_asan<ET, I, S>(
_qemu: Qemu,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
_id: u64,
_addr: GuestAddr,
) where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
panic!("I really shouldn't be here");
}
#[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly
fn guest_trace_error_n_asan<ET, S>(
fn guest_trace_error_n_asan<ET, I, S>(
_qemu: Qemu,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
_id: u64,
_addr: GuestAddr,
_n: usize,
) where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
panic!("I really shouldn't be here either");
}
impl<F, S> EmulatorModule<S> for AsanGuestModule<F>
impl<F, I, S> EmulatorModule<I, S> for AsanGuestModule<F>
where
F: AddressFilter,
S: Unpin + UsesInput,
I: Unpin,
S: Unpin,
{
type ModuleAddressFilter = F;
fn pre_qemu_init<ET>(
&mut self,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
qemu_params: &mut QemuParams,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
let mut args = qemu_params.to_cli();
@ -265,9 +268,9 @@ where
self.asan_lib = Some(asan_lib);
}
fn post_qemu_init<ET>(&mut self, qemu: Qemu, _emulator_modules: &mut EmulatorModules<ET, S>)
fn post_qemu_init<ET>(&mut self, qemu: Qemu, _emulator_modules: &mut EmulatorModules<ET, I, S>)
where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
for mapping in qemu.mappings() {
println!("mapping: {mapping:#?}");
@ -306,28 +309,29 @@ where
fn first_exec<ET>(
&mut self,
_qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S,
) where
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
emulator_modules.reads(
Hook::Function(gen_readwrite_guest_asan::<ET, F, S>),
Hook::Function(guest_trace_error_asan::<ET, S>),
Hook::Function(guest_trace_error_asan::<ET, S>),
Hook::Function(guest_trace_error_asan::<ET, S>),
Hook::Function(guest_trace_error_asan::<ET, S>),
Hook::Function(guest_trace_error_n_asan::<ET, S>),
Hook::Function(gen_readwrite_guest_asan::<ET, F, I, S>),
Hook::Function(guest_trace_error_asan::<ET, I, S>),
Hook::Function(guest_trace_error_asan::<ET, I, S>),
Hook::Function(guest_trace_error_asan::<ET, I, S>),
Hook::Function(guest_trace_error_asan::<ET, I, S>),
Hook::Function(guest_trace_error_n_asan::<ET, I, S>),
);
emulator_modules.writes(
Hook::Function(gen_readwrite_guest_asan::<ET, F, S>),
Hook::Function(guest_trace_error_asan::<ET, S>),
Hook::Function(guest_trace_error_asan::<ET, S>),
Hook::Function(guest_trace_error_asan::<ET, S>),
Hook::Function(guest_trace_error_asan::<ET, S>),
Hook::Function(guest_trace_error_n_asan::<ET, S>),
Hook::Function(gen_readwrite_guest_asan::<ET, F, I, S>),
Hook::Function(guest_trace_error_asan::<ET, I, S>),
Hook::Function(guest_trace_error_asan::<ET, I, S>),
Hook::Function(guest_trace_error_asan::<ET, I, S>),
Hook::Function(guest_trace_error_asan::<ET, I, S>),
Hook::Function(guest_trace_error_n_asan::<ET, I, S>),
);
}

View File

@ -14,7 +14,7 @@
use std::{ffi::CStr, fmt::Display, fs, os::raw::c_char, path::Path};
use hashbrown::HashMap;
use libafl::{inputs::UsesInput, Error};
use libafl::Error;
use libafl_qemu_sys::GuestAddr;
use serde::{Deserialize, Serialize};
@ -214,14 +214,15 @@ impl InjectionModule {
})
}
fn on_call_check<ET, S>(
fn on_call_check<ET, I, S>(
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
id: usize,
parameter: u8,
) where
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
let reg: GuestAddr = qemu
.current_cpu()
@ -262,26 +263,27 @@ impl InjectionModule {
}
}
impl<S> EmulatorModule<S> for InjectionModule
impl<I, S> EmulatorModule<I, S> for InjectionModule
where
S: Unpin + UsesInput,
I: Unpin,
S: Unpin,
{
type ModuleAddressFilter = NopAddressFilter;
fn post_qemu_init<ET>(&mut self, _qemu: Qemu, emulator_modules: &mut EmulatorModules<ET, S>)
fn post_qemu_init<ET>(&mut self, _qemu: Qemu, emulator_modules: &mut EmulatorModules<ET, I, S>)
where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
emulator_modules.pre_syscalls(Hook::Function(syscall_hook::<ET, S>));
emulator_modules.pre_syscalls(Hook::Function(syscall_hook::<ET, I, S>));
}
fn first_exec<ET>(
&mut self,
qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
let mut libs: Vec<LibInfo> = Vec::new();
@ -354,10 +356,10 @@ where
#[expect(clippy::too_many_arguments)]
#[allow(clippy::needless_pass_by_value)] // no longer a problem with nightly
fn syscall_hook<ET, S>(
fn syscall_hook<ET, I, S>(
// Our instantiated [`EmulatorModules`]
_qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
// Syscall number
syscall: i32,
@ -372,8 +374,9 @@ fn syscall_hook<ET, S>(
_x7: GuestAddr,
) -> SyscallHookResult
where
ET: EmulatorModuleTuple<S>,
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
log::trace!("syscall_hook {syscall} {SYS_execve}");
debug_assert!(i32::try_from(SYS_execve).is_ok());

View File

@ -2,7 +2,6 @@
use std::{cell::UnsafeCell, mem::MaybeUninit, sync::Mutex};
use hashbrown::{HashMap, HashSet};
use libafl::inputs::UsesInput;
use libafl_qemu_sys::{GuestAddr, MmapPerms};
use meminterval::{Interval, IntervalTree};
use thread_local::ThreadLocal;
@ -694,42 +693,43 @@ impl Default for SnapshotModule {
}
}
impl<S> EmulatorModule<S> for SnapshotModule
impl<I, S> EmulatorModule<I, S> for SnapshotModule
where
S: Unpin + UsesInput,
I: Unpin,
S: Unpin,
{
type ModuleAddressFilter = NopAddressFilter;
fn post_qemu_init<ET>(&mut self, _qemu: Qemu, emulator_modules: &mut EmulatorModules<ET, S>)
fn post_qemu_init<ET>(&mut self, _qemu: Qemu, emulator_modules: &mut EmulatorModules<ET, I, S>)
where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
if emulator_modules.get::<AsanModule>().is_none() {
// The ASan module, if present, will call the tracer hook for the snapshot helper as opt
emulator_modules.writes(
Hook::Empty,
Hook::Function(trace_write_snapshot::<ET, S, 1>),
Hook::Function(trace_write_snapshot::<ET, S, 2>),
Hook::Function(trace_write_snapshot::<ET, S, 4>),
Hook::Function(trace_write_snapshot::<ET, S, 8>),
Hook::Function(trace_write_n_snapshot::<ET, S>),
Hook::Function(trace_write_snapshot::<ET, I, S, 1>),
Hook::Function(trace_write_snapshot::<ET, I, S, 2>),
Hook::Function(trace_write_snapshot::<ET, I, S, 4>),
Hook::Function(trace_write_snapshot::<ET, I, S, 8>),
Hook::Function(trace_write_n_snapshot::<ET, I, S>),
);
}
if !self.accurate_unmap {
emulator_modules.pre_syscalls(Hook::Function(filter_mmap_snapshot::<ET, S>));
emulator_modules.pre_syscalls(Hook::Function(filter_mmap_snapshot::<ET, I, S>));
}
emulator_modules.post_syscalls(Hook::Function(trace_mmap_snapshot::<ET, S>));
emulator_modules.post_syscalls(Hook::Function(trace_mmap_snapshot::<ET, I, S>));
}
fn pre_exec<ET>(
&mut self,
qemu: Qemu,
_emulator_modules: &mut EmulatorModules<ET, S>,
_emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: &mut S,
_input: &S::Input,
_input: &I,
) where
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
{
if self.empty {
self.snapshot(qemu);
@ -747,39 +747,41 @@ where
}
}
pub fn trace_write_snapshot<ET, S, const SIZE: usize>(
pub fn trace_write_snapshot<ET, I, S, const SIZE: usize>(
_qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
_id: u64,
addr: GuestAddr,
) where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
let h = emulator_modules.get_mut::<SnapshotModule>().unwrap();
h.access(addr, SIZE);
}
pub fn trace_write_n_snapshot<ET, S>(
pub fn trace_write_n_snapshot<ET, I, S>(
_qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
_id: u64,
addr: GuestAddr,
size: usize,
) where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
let h = emulator_modules.get_mut::<SnapshotModule>().unwrap();
h.access(addr, size);
}
#[expect(clippy::too_many_arguments)]
pub fn filter_mmap_snapshot<ET, S>(
pub fn filter_mmap_snapshot<ET, I, S>(
_qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
sys_num: i32,
a0: GuestAddr,
@ -792,8 +794,9 @@ pub fn filter_mmap_snapshot<ET, S>(
_a7: GuestAddr,
) -> SyscallHookResult
where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
if i64::from(sys_num) == SYS_munmap {
let h = emulator_modules.get_mut::<SnapshotModule>().unwrap();
@ -805,9 +808,9 @@ where
}
#[expect(non_upper_case_globals, clippy::too_many_arguments)]
pub fn trace_mmap_snapshot<ET, S>(
pub fn trace_mmap_snapshot<ET, I, S>(
_qemu: Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
_state: Option<&mut S>,
result: GuestAddr,
sys_num: i32,
@ -821,8 +824,9 @@ pub fn trace_mmap_snapshot<ET, S>(
_a7: GuestAddr,
) -> GuestAddr
where
S: Unpin + UsesInput,
ET: EmulatorModuleTuple<S>,
ET: EmulatorModuleTuple<I, S>,
I: Unpin,
S: Unpin,
{
// NOT A COMPLETE LIST OF MEMORY EFFECTS
match i64::from(sys_num) {

View File

@ -260,11 +260,7 @@ pub(crate) static mut NOP_PAGE_FILTER: UnsafeCell<NopPageFilter> = UnsafeCell::n
#[cfg(all(feature = "systemmode", test))]
mod tests {
use libafl::{
inputs::{NopInput, UsesInput},
state::NopState,
HasMetadata,
};
use libafl::{inputs::NopInput, state::NopState, HasMetadata};
use libafl_bolts::tuples::tuple_list;
use crate::modules::{
@ -281,11 +277,12 @@ mod tests {
page_filter: PF,
}
impl<S, AF, PF> EmulatorModule<S> for DummyModule<AF, PF>
impl<I, S, AF, PF> EmulatorModule<I, S> for DummyModule<AF, PF>
where
AF: AddressFilter + 'static,
PF: PageFilter + 'static,
S: Unpin + UsesInput + HasMetadata,
I: Unpin,
S: Unpin + HasMetadata,
{
type ModuleAddressFilter = AF;
type ModulePageFilter = PF;
@ -307,14 +304,15 @@ mod tests {
}
}
fn gen_module<AF, PF, S>(
fn gen_module<AF, PF, I, S>(
af: AF,
pf: PF,
) -> impl EmulatorModule<S, ModuleAddressFilter = AF, ModulePageFilter = PF>
) -> impl EmulatorModule<I, S, ModuleAddressFilter = AF, ModulePageFilter = PF>
where
AF: AddressFilter,
PF: PageFilter,
S: HasMetadata + UsesInput + Unpin,
I: Unpin,
S: HasMetadata + Unpin,
{
DummyModule {
address_filter: af,

View File

@ -5,7 +5,7 @@
use core::{ffi::c_void, fmt::Debug, mem::transmute, ptr};
use libafl::{executors::hooks::inprocess::inprocess_get_state, inputs::UsesInput};
use libafl::executors::hooks::inprocess::inprocess_get_state;
#[cfg(feature = "usermode")]
use libafl_qemu_sys::libafl_dump_core_hook;
use libafl_qemu_sys::{CPUArchStatePtr, CPUStatePtr, FatPtr, GuestAddr, GuestUsize};
@ -103,24 +103,26 @@ impl<F, C, R: Clone> Hook<F, C, R> {
macro_rules! create_pre_init_wrapper {
($name:ident, ($($param:ident : $param_type:ty),*)) => {
paste::paste! {
pub extern "C" fn [<func_ $name _hook_wrapper>]<ET, S>(hook: &mut (), $($param: $param_type),*)
pub extern "C" fn [<func_ $name _hook_wrapper>]<ET, I, S>(hook: &mut (), $($param: $param_type),*)
where
S: UsesInput + Unpin,
I: Unpin,
S: Unpin,
{
unsafe {
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
let func: fn(&mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*) = transmute(ptr::from_mut::<()>(hook));
let modules = EmulatorModules::<ET, I, S>::emulator_modules_mut_unchecked();
let func: fn(&mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*) = transmute(ptr::from_mut::<()>(hook));
func(modules, inprocess_get_state::<S>(), $($param),*);
}
}
pub extern "C" fn [<closure_ $name _hook_wrapper>]<ET, S>(hook: &mut FatPtr, $($param: $param_type),*)
pub extern "C" fn [<closure_ $name _hook_wrapper>]<ET, I, S>(hook: &mut FatPtr, $($param: $param_type),*)
where
S: Unpin + UsesInput,
I: Unpin,
S: Unpin,
{
unsafe {
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
let func: &mut Box<dyn FnMut(&mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*)> = &mut *(ptr::from_mut::<FatPtr>(hook) as *mut Box<dyn FnMut(&mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*)>);
let modules = EmulatorModules::<ET, I, S>::emulator_modules_mut_unchecked();
let func: &mut Box<dyn FnMut(&mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*)> = &mut *(ptr::from_mut::<FatPtr>(hook) as *mut Box<dyn FnMut(&mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*)>);
func(modules, inprocess_get_state::<S>(), $($param),*);
}
}
@ -128,24 +130,26 @@ macro_rules! create_pre_init_wrapper {
};
($name:ident, ($($param:ident : $param_type:ty),*), $ret_type:ty) => {
paste::paste! {
pub extern "C" fn [<func_ $name _hook_wrapper>]<ET, S>(hook: &mut (), $($param: $param_type),*) -> $ret_type
pub extern "C" fn [<func_ $name _hook_wrapper>]<ET, I, S>(hook: &mut (), $($param: $param_type),*) -> $ret_type
where
S: UsesInput + Unpin,
I: Unpin,
S: Unpin,
{
unsafe {
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
let func: fn(&mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*) -> $ret_type= transmute(ptr::from_mut::<()>(hook));
let modules = EmulatorModules::<ET, I, S>::emulator_modules_mut_unchecked();
let func: fn(&mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*) -> $ret_type= transmute(ptr::from_mut::<()>(hook));
func(modules, inprocess_get_state::<S>(), $($param),*)
}
}
pub extern "C" fn [<closure_ $name _hook_wrapper>]<ET, S>(hook: &mut FatPtr, $($param: $param_type),*) -> $ret_type
pub extern "C" fn [<closure_ $name _hook_wrapper>]<ET, I, S>(hook: &mut FatPtr, $($param: $param_type),*) -> $ret_type
where
S: UsesInput + Unpin,
I: Unpin,
S: Unpin,
{
unsafe {
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
let func: &mut Box<dyn FnMut(&mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*) -> $ret_type> = &mut *(ptr::from_mut::<FatPtr>(hook) as *mut Box<dyn FnMut(&mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*) -> $ret_type>);
let modules = EmulatorModules::<ET, I, S>::emulator_modules_mut_unchecked();
let func: &mut Box<dyn FnMut(&mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*) -> $ret_type> = &mut *(ptr::from_mut::<FatPtr>(hook) as *mut Box<dyn FnMut(&mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*) -> $ret_type>);
func(modules, inprocess_get_state::<S>(), $($param),*)
}
}
@ -156,26 +160,28 @@ macro_rules! create_pre_init_wrapper {
macro_rules! create_wrapper {
($name:ident, ($($param:ident : $param_type:ty),*)) => {
paste::paste! {
pub extern "C" fn [<func_ $name _hook_wrapper>]<ET, S>(hook: &mut (), $($param: $param_type),*)
pub extern "C" fn [<func_ $name _hook_wrapper>]<ET, I, S>(hook: &mut (), $($param: $param_type),*)
where
S: UsesInput + Unpin,
I: Unpin,
S: Unpin,
{
unsafe {
let qemu = Qemu::get_unchecked();
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
let func: fn(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*) = transmute(ptr::from_mut::<()>(hook));
let modules = EmulatorModules::<ET, I, S>::emulator_modules_mut_unchecked();
let func: fn(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*) = transmute(ptr::from_mut::<()>(hook));
func(qemu, modules, inprocess_get_state::<S>(), $($param),*);
}
}
pub extern "C" fn [<closure_ $name _hook_wrapper>]<ET, S>(hook: &mut FatPtr, $($param: $param_type),*)
pub extern "C" fn [<closure_ $name _hook_wrapper>]<ET, I, S>(hook: &mut FatPtr, $($param: $param_type),*)
where
S: Unpin + UsesInput,
I: Unpin,
S: Unpin,
{
unsafe {
let qemu = Qemu::get_unchecked();
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
let func: &mut Box<dyn FnMut(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*)> = &mut *(ptr::from_mut::<FatPtr>(hook) as *mut Box<dyn FnMut(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*)>);
let modules = EmulatorModules::<ET, I, S>::emulator_modules_mut_unchecked();
let func: &mut Box<dyn FnMut(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*)> = &mut *(ptr::from_mut::<FatPtr>(hook) as *mut Box<dyn FnMut(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*)>);
func(qemu, modules, inprocess_get_state::<S>(), $($param),*);
}
}
@ -183,26 +189,28 @@ macro_rules! create_wrapper {
};
($name:ident, ($($param:ident : $param_type:ty),*), $ret_type:ty) => {
paste::paste! {
pub extern "C" fn [<func_ $name _hook_wrapper>]<ET, S>(hook: &mut (), $($param: $param_type),*) -> $ret_type
pub extern "C" fn [<func_ $name _hook_wrapper>]<ET, I, S>(hook: &mut (), $($param: $param_type),*) -> $ret_type
where
S: UsesInput + Unpin,
I: Unpin,
S: Unpin,
{
unsafe {
let qemu = Qemu::get_unchecked();
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
let func: fn(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*) -> $ret_type= transmute(ptr::from_mut::<()>(hook));
let modules = EmulatorModules::<ET, I, S>::emulator_modules_mut_unchecked();
let func: fn(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*) -> $ret_type= transmute(ptr::from_mut::<()>(hook));
func(qemu, modules, inprocess_get_state::<S>(), $($param),*)
}
}
pub extern "C" fn [<closure_ $name _hook_wrapper>]<ET, S>(hook: &mut FatPtr, $($param: $param_type),*) -> $ret_type
pub extern "C" fn [<closure_ $name _hook_wrapper>]<ET, I, S>(hook: &mut FatPtr, $($param: $param_type),*) -> $ret_type
where
S: UsesInput + Unpin,
I: Unpin,
S: Unpin,
{
unsafe {
let qemu = Qemu::get_unchecked();
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
let func: &mut Box<dyn FnMut(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*) -> $ret_type> = &mut *(ptr::from_mut::<FatPtr>(hook) as *mut Box<dyn FnMut(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*) -> $ret_type>);
let modules = EmulatorModules::<ET, I, S>::emulator_modules_mut_unchecked();
let func: &mut Box<dyn FnMut(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*) -> $ret_type> = &mut *(ptr::from_mut::<FatPtr>(hook) as *mut Box<dyn FnMut(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*) -> $ret_type>);
func(qemu, modules, inprocess_get_state::<S>(), $($param),*)
}
}
@ -213,25 +221,26 @@ macro_rules! create_wrapper {
macro_rules! create_pre_exec_wrapper {
($name:ident, ($($param:ident : $param_type:ty),*), $hook_id:ident) => {
paste::paste! {
pub extern "C" fn [<$name _pre_exec_hook_wrapper>]<ET, S>(hook: &mut HookState<$hook_id>, $($param: $param_type),*)
pub extern "C" fn [<$name _pre_exec_hook_wrapper>]<ET, I, S>(hook: &mut HookState<$hook_id>, $($param: $param_type),*)
where
S: UsesInput + Unpin,
I: Unpin,
S: Unpin,
{
unsafe {
let qemu = Qemu::get_unchecked();
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
let modules = EmulatorModules::<ET, I, S>::emulator_modules_mut_unchecked();
match &mut hook.pre_run {
HookRepr::Function(ptr) => {
let func: fn(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*) =
let func: fn(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*) =
transmute(*ptr);
func(qemu, modules, inprocess_get_state::<S>(), $($param),*)
}
HookRepr::Closure(ptr) => {
let func: &mut Box<
dyn FnMut(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*),
dyn FnMut(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*),
> = &mut *(ptr::from_mut::<FatPtr>(ptr) as *mut Box<
dyn FnMut(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*),
dyn FnMut(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*),
>);
func(qemu, modules, inprocess_get_state::<S>(), $($param),*)
}
@ -246,25 +255,26 @@ macro_rules! create_pre_exec_wrapper {
macro_rules! create_post_exec_wrapper {
($name:ident, ($($param:ident : $param_type:ty),*), $hook_id:ident) => {
paste::paste! {
pub extern "C" fn [<$name _post_exec_hook_wrapper>]<ET, S>(hook: &mut HookState<$hook_id>, $($param: $param_type),*)
pub extern "C" fn [<$name _post_exec_hook_wrapper>]<ET, I, S>(hook: &mut HookState<$hook_id>, $($param: $param_type),*)
where
S: UsesInput + Unpin,
I: Unpin,
S: Unpin,
{
unsafe {
let qemu = Qemu::get_unchecked();
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
let modules = EmulatorModules::<ET, I, S>::emulator_modules_mut_unchecked();
match &mut hook.post_run {
HookRepr::Function(ptr) => {
let func: fn(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*) =
let func: fn(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*) =
transmute(*ptr);
func(qemu, modules, inprocess_get_state::<S>(), $($param),*);
}
HookRepr::Closure(ptr) => {
let func: &mut Box<
dyn FnMut(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*),
dyn FnMut(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*),
> = &mut *(ptr::from_mut::<FatPtr>(ptr) as *mut Box<
dyn FnMut(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*),
dyn FnMut(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*),
>);
func(qemu, modules, inprocess_get_state::<S>(), $($param),*);
}
@ -279,24 +289,25 @@ macro_rules! create_post_exec_wrapper {
macro_rules! create_gen_wrapper {
($name:ident, ($($param:ident : $param_type:ty),*), $ret_type:ty, $execs:literal, $hook_id:ident) => {
paste::paste! {
pub extern "C" fn [<$name _gen_hook_wrapper>]<ET, S>(hook: &mut TcgHookState<{ $execs }, $hook_id>, $($param: $param_type),*) -> $ret_type
pub extern "C" fn [<$name _gen_hook_wrapper>]<ET, I, S>(hook: &mut TcgHookState<{ $execs }, $hook_id>, $($param: $param_type),*) -> $ret_type
where
S: UsesInput + Unpin,
I: Unpin,
S: Unpin,
{
unsafe {
let qemu = Qemu::get_unchecked();
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
let modules = EmulatorModules::<ET, I, S>::emulator_modules_mut_unchecked();
match &mut hook.gen {
HookRepr::Function(ptr) => {
let func: fn(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*) -> Option<$ret_type> =
let func: fn(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*) -> Option<$ret_type> =
transmute(*ptr);
func(qemu, modules, inprocess_get_state::<S>(), $($param),*).map_or(SKIP_EXEC_HOOK, |id| id)
}
HookRepr::Closure(ptr) => {
let func: &mut Box<
dyn FnMut(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*) -> Option<$ret_type>,
> = &mut *(ptr::from_mut::<FatPtr>(ptr) as *mut Box<dyn FnMut(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*) -> Option<$ret_type>>);
dyn FnMut(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*) -> Option<$ret_type>,
> = &mut *(ptr::from_mut::<FatPtr>(ptr) as *mut Box<dyn FnMut(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*) -> Option<$ret_type>>);
func(qemu, modules, inprocess_get_state::<S>(), $($param),*).map_or(SKIP_EXEC_HOOK, |id| id)
}
_ => 0,
@ -310,24 +321,25 @@ macro_rules! create_gen_wrapper {
macro_rules! create_post_gen_wrapper {
($name:ident, ($($param:ident : $param_type:ty),*), $execs:literal, $hook_id:ident) => {
paste::paste! {
pub extern "C" fn [<$name _post_gen_hook_wrapper>]<ET, S>(hook: &mut TcgHookState<{ $execs }, $hook_id>, $($param: $param_type),*)
pub extern "C" fn [<$name _post_gen_hook_wrapper>]<ET, I, S>(hook: &mut TcgHookState<{ $execs }, $hook_id>, $($param: $param_type),*)
where
S: UsesInput + Unpin,
I: Unpin,
S: Unpin,
{
unsafe {
let qemu = Qemu::get_unchecked();
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
let modules = EmulatorModules::<ET, I, S>::emulator_modules_mut_unchecked();
match &mut hook.post_gen {
HookRepr::Function(ptr) => {
let func: fn(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*) =
let func: fn(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*) =
transmute(*ptr);
func(qemu, modules, inprocess_get_state::<S>(), $($param),*);
}
HookRepr::Closure(ptr) => {
let func: &mut Box<
dyn FnMut(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*),
> = &mut *(ptr::from_mut::<FatPtr>(ptr) as *mut Box<dyn FnMut(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*)>);
dyn FnMut(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*),
> = &mut *(ptr::from_mut::<FatPtr>(ptr) as *mut Box<dyn FnMut(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*)>);
func(qemu, modules, inprocess_get_state::<S>(), $($param),*);
}
_ => (),
@ -341,22 +353,23 @@ macro_rules! create_post_gen_wrapper {
macro_rules! create_exec_wrapper {
($name:ident, ($($param:ident : $param_type:ty),*), $execidx:literal, $execs:literal, $hook_id:ident) => {
paste::paste! {
pub extern "C" fn [<$name _ $execidx _exec_hook_wrapper>]<ET, S>(hook: &mut TcgHookState<{ $execs }, $hook_id>, $($param: $param_type),*)
pub extern "C" fn [<$name _ $execidx _exec_hook_wrapper>]<ET, I, S>(hook: &mut TcgHookState<{ $execs }, $hook_id>, $($param: $param_type),*)
where
S: UsesInput + Unpin,
I: Unpin,
S: Unpin,
{
unsafe {
let qemu = Qemu::get_unchecked();
let modules = EmulatorModules::<ET, S>::emulator_modules_mut_unchecked();
let modules = EmulatorModules::<ET, I, S>::emulator_modules_mut_unchecked();
match &mut hook.execs[$execidx] {
HookRepr::Function(ptr) => {
let func: fn(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*) = transmute(*ptr);
let func: fn(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*) = transmute(*ptr);
func(qemu, modules, inprocess_get_state::<S>(), $($param),*);
}
HookRepr::Closure(ptr) => {
let func: &mut Box<dyn FnMut(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*)> =
&mut *(ptr::from_mut::<FatPtr>(ptr) as *mut Box<dyn FnMut(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, $($param_type),*)>);
let func: &mut Box<dyn FnMut(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*)> =
&mut *(ptr::from_mut::<FatPtr>(ptr) as *mut Box<dyn FnMut(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, $($param_type),*)>);
func(qemu, modules, inprocess_get_state::<S>(), $($param),*);
}
_ => (),
@ -407,13 +420,13 @@ macro_rules! create_hook_id {
macro_rules! create_hook_types {
($name:ident, $fn_type:ty, $closure_type:ty, $raw_type:ty) => {
paste::paste! {
pub type [<$name HookFn>]<ET, S> = $fn_type;
pub type [<$name HookClosure>]<ET, S> = $closure_type;
pub type [<$name HookFn>]<ET, I, S> = $fn_type;
pub type [<$name HookClosure>]<ET, I, S> = $closure_type;
pub type [<$name HookRaw>] = $raw_type;
pub type [<$name Hook>]<ET, S> = Hook<
[<$name HookFn>]<ET, S>,
[<$name HookClosure>]<ET, S>,
pub type [<$name Hook>]<ET, I, S> = Hook<
[<$name HookFn>]<ET, I, S>,
[<$name HookClosure>]<ET, I, S>,
[<$name HookRaw>],
>;
}
@ -423,8 +436,8 @@ macro_rules! create_hook_types {
// Instruction hook wrappers
create_hook_types!(
Instruction,
fn(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, GuestAddr),
Box<dyn for<'a> FnMut(Qemu, &'a mut EmulatorModules<ET, S>, Option<&'a mut S>, GuestAddr)>,
fn(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, GuestAddr),
Box<dyn for<'a> FnMut(Qemu, &'a mut EmulatorModules<ET, I, S>, Option<&'a mut S>, GuestAddr)>,
extern "C" fn(*const (), pc: GuestAddr)
);
create_hook_id!(Instruction, libafl_qemu_remove_instruction_hook, true);
@ -433,8 +446,8 @@ create_wrapper!(instruction, (pc: GuestAddr));
// Backdoor hook wrappers
create_hook_types!(
Backdoor,
fn(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, cpu: CPUArchStatePtr, GuestAddr),
Box<dyn for<'a> FnMut(Qemu, &'a mut EmulatorModules<ET, S>, Option<&'a mut S>, GuestAddr)>,
fn(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, cpu: CPUArchStatePtr, GuestAddr),
Box<dyn for<'a> FnMut(Qemu, &'a mut EmulatorModules<ET, I, S>, Option<&'a mut S>, GuestAddr)>,
extern "C" fn(libafl_qemu_opaque: *const (), cpu: CPUArchStatePtr, pc: GuestAddr)
);
create_hook_id!(Backdoor, libafl_qemu_remove_backdoor_hook, true);
@ -446,7 +459,7 @@ create_hook_types!(
PreSyscall,
fn(
Qemu,
&mut EmulatorModules<ET, S>,
&mut EmulatorModules<ET, I, S>,
Option<&mut S>,
sys_num: i32,
a0: GuestAddr,
@ -461,7 +474,7 @@ create_hook_types!(
Box<
dyn for<'a> FnMut(
Qemu,
&'a mut EmulatorModules<ET, S>,
&'a mut EmulatorModules<ET, I, S>,
Option<&'a mut S>,
i32,
GuestAddr,
@ -512,7 +525,7 @@ create_hook_types!(
PostSyscall,
fn(
Qemu,
&mut EmulatorModules<ET, S>,
&mut EmulatorModules<ET, I, S>,
Option<&mut S>,
res: GuestAddr,
sys_num: i32,
@ -528,7 +541,7 @@ create_hook_types!(
Box<
dyn for<'a> FnMut(
Qemu,
&'a mut EmulatorModules<ET, S>,
&'a mut EmulatorModules<ET, I, S>,
Option<&mut S>,
GuestAddr,
i32,
@ -579,10 +592,10 @@ create_wrapper!(
// New thread hook wrappers
create_hook_types!(
NewThread,
fn(&mut EmulatorModules<ET, S>, Option<&mut S>, env: CPUArchStatePtr, tid: u32) -> bool,
fn(&mut EmulatorModules<ET, I, S>, Option<&mut S>, env: CPUArchStatePtr, tid: u32) -> bool,
Box<
dyn for<'a> FnMut(
&'a mut EmulatorModules<ET, S>,
&'a mut EmulatorModules<ET, I, S>,
Option<&'a mut S>,
CPUArchStatePtr,
u32,
@ -596,14 +609,14 @@ create_pre_init_wrapper!(new_thread, (env: CPUArchStatePtr, tid: u32), bool);
// CPU Run hook wrappers
create_hook_types!(
CpuPreRun,
fn(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, cpu: CPUStatePtr),
Box<dyn for<'a> FnMut(Qemu, &'a mut EmulatorModules<ET, S>, Option<&'a mut S>, CPUStatePtr)>,
fn(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, cpu: CPUStatePtr),
Box<dyn for<'a> FnMut(Qemu, &'a mut EmulatorModules<ET, I, S>, Option<&'a mut S>, CPUStatePtr)>,
extern "C" fn(libafl_qemu_opaque: *const (), cpu: CPUStatePtr)
);
create_hook_types!(
CpuPostRun,
fn(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, cpu: CPUStatePtr),
Box<dyn for<'a> FnMut(Qemu, &'a mut EmulatorModules<ET, S>, Option<&'a mut S>, CPUStatePtr)>,
fn(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, cpu: CPUStatePtr),
Box<dyn for<'a> FnMut(Qemu, &'a mut EmulatorModules<ET, I, S>, Option<&'a mut S>, CPUStatePtr)>,
extern "C" fn(libafl_qemu_opaque: *const (), cpu: CPUStatePtr)
);
create_hook_id!(CpuRun, libafl_qemu_remove_cpu_run_hook, false);
@ -616,7 +629,7 @@ create_hook_types!(
EdgeGen,
fn(
Qemu,
&mut EmulatorModules<ET, S>,
&mut EmulatorModules<ET, I, S>,
Option<&mut S>,
src: GuestAddr,
dest: GuestAddr,
@ -624,7 +637,7 @@ create_hook_types!(
Box<
dyn for<'a> FnMut(
Qemu,
&'a mut EmulatorModules<ET, S>,
&'a mut EmulatorModules<ET, I, S>,
Option<&'a mut S>,
GuestAddr,
GuestAddr,
@ -634,8 +647,8 @@ create_hook_types!(
);
create_hook_types!(
EdgeExec,
fn(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, id: u64),
Box<dyn for<'a> FnMut(Qemu, &'a mut EmulatorModules<ET, S>, Option<&'a mut S>, u64)>,
fn(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, id: u64),
Box<dyn for<'a> FnMut(Qemu, &'a mut EmulatorModules<ET, I, S>, Option<&'a mut S>, u64)>,
unsafe extern "C" fn(libafl_qemu_opaque: *const (), id: u64)
);
create_hook_id!(Edge, libafl_qemu_remove_edge_hook, true);
@ -645,11 +658,11 @@ create_exec_wrapper!(edge, (id: u64), 0, 1, EdgeHookId);
// Block hook wrappers
create_hook_types!(
BlockGen,
fn(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, pc: GuestAddr) -> Option<u64>,
fn(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, pc: GuestAddr) -> Option<u64>,
Box<
dyn for<'a> FnMut(
Qemu,
&'a mut EmulatorModules<ET, S>,
&'a mut EmulatorModules<ET, I, S>,
Option<&'a mut S>,
GuestAddr,
) -> Option<u64>,
@ -658,11 +671,17 @@ create_hook_types!(
);
create_hook_types!(
BlockPostGen,
fn(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, pc: GuestAddr, block_length: GuestUsize),
fn(
Qemu,
&mut EmulatorModules<ET, I, S>,
Option<&mut S>,
pc: GuestAddr,
block_length: GuestUsize,
),
Box<
dyn for<'a> FnMut(
Qemu,
&'a mut EmulatorModules<ET, S>,
&'a mut EmulatorModules<ET, I, S>,
Option<&mut S>,
GuestAddr,
GuestUsize,
@ -672,8 +691,8 @@ create_hook_types!(
);
create_hook_types!(
BlockExec,
fn(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, id: u64),
Box<dyn for<'a> FnMut(Qemu, &'a mut EmulatorModules<ET, S>, Option<&'a mut S>, u64)>,
fn(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, id: u64),
Box<dyn for<'a> FnMut(Qemu, &'a mut EmulatorModules<ET, I, S>, Option<&'a mut S>, u64)>,
unsafe extern "C" fn(libafl_qemu_opaque: *const (), id: u64)
);
@ -687,7 +706,7 @@ create_hook_types!(
ReadGen,
fn(
Qemu,
emulator_modules: &mut EmulatorModules<ET, S>,
emulator_modules: &mut EmulatorModules<ET, I, S>,
Option<&mut S>,
pc: GuestAddr,
addr: *mut TCGTemp,
@ -696,7 +715,7 @@ create_hook_types!(
Box<
dyn for<'a> FnMut(
Qemu,
&'a mut EmulatorModules<ET, S>,
&'a mut EmulatorModules<ET, I, S>,
Option<&'a mut S>,
GuestAddr,
*mut TCGTemp,
@ -712,17 +731,25 @@ create_hook_types!(
);
create_hook_types!(
ReadExec,
fn(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, id: u64, addr: GuestAddr),
Box<dyn for<'a> FnMut(Qemu, &'a mut EmulatorModules<ET, S>, Option<&'a mut S>, u64, GuestAddr)>,
fn(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, id: u64, addr: GuestAddr),
Box<
dyn for<'a> FnMut(
Qemu,
&'a mut EmulatorModules<ET, I, S>,
Option<&'a mut S>,
u64,
GuestAddr,
),
>,
unsafe extern "C" fn(libafl_qemu_opaque: *const (), id: u64, addr: GuestAddr)
);
create_hook_types!(
ReadExecN,
fn(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, id: u64, addr: GuestAddr, size: usize),
fn(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, id: u64, addr: GuestAddr, size: usize),
Box<
dyn for<'a> FnMut(
Qemu,
&'a mut EmulatorModules<ET, S>,
&'a mut EmulatorModules<ET, I, S>,
Option<&'a mut S>,
u64,
GuestAddr,
@ -750,7 +777,7 @@ create_hook_types!(
WriteGen,
fn(
Qemu,
&mut EmulatorModules<ET, S>,
&mut EmulatorModules<ET, I, S>,
Option<&mut S>,
pc: GuestAddr,
addr: *mut TCGTemp,
@ -759,7 +786,7 @@ create_hook_types!(
Box<
dyn for<'a> FnMut(
Qemu,
&'a mut EmulatorModules<ET, S>,
&'a mut EmulatorModules<ET, I, S>,
Option<&'a mut S>,
GuestAddr,
*mut TCGTemp,
@ -775,17 +802,25 @@ create_hook_types!(
);
create_hook_types!(
WriteExec,
fn(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, id: u64, addr: GuestAddr),
Box<dyn for<'a> FnMut(Qemu, &'a mut EmulatorModules<ET, S>, Option<&'a mut S>, u64, GuestAddr)>,
fn(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, id: u64, addr: GuestAddr),
Box<
dyn for<'a> FnMut(
Qemu,
&'a mut EmulatorModules<ET, I, S>,
Option<&'a mut S>,
u64,
GuestAddr,
),
>,
unsafe extern "C" fn(libafl_qemu_opaque: *const (), id: u64, addr: GuestAddr)
);
create_hook_types!(
WriteExecN,
fn(Qemu, &mut EmulatorModules<ET, S>, Option<&mut S>, id: u64, addr: GuestAddr, size: usize),
fn(Qemu, &mut EmulatorModules<ET, I, S>, Option<&mut S>, id: u64, addr: GuestAddr, size: usize),
Box<
dyn for<'a> FnMut(
Qemu,
&'a mut EmulatorModules<ET, S>,
&'a mut EmulatorModules<ET, I, S>,
Option<&'a mut S>,
u64,
GuestAddr,
@ -813,7 +848,7 @@ create_hook_types!(
CmpGen,
fn(
Qemu,
&mut EmulatorModules<ET, S>,
&mut EmulatorModules<ET, I, S>,
Option<&mut S>,
pc: GuestAddr,
size: usize,
@ -821,7 +856,7 @@ create_hook_types!(
Box<
dyn for<'a> FnMut(
Qemu,
&'a mut EmulatorModules<ET, S>,
&'a mut EmulatorModules<ET, I, S>,
Option<&'a mut S>,
GuestAddr,
usize,
@ -829,9 +864,9 @@ create_hook_types!(
>,
unsafe extern "C" fn(libafl_qemu_opaque: *const (), pc: GuestAddr, size: usize) -> u64
);
pub type CmpExecHook<ET, S, SZ> = Hook<
fn(&mut EmulatorModules<ET, S>, Option<&mut S>, id: u64, v0: SZ, v1: SZ),
Box<dyn for<'a> FnMut(&'a mut EmulatorModules<ET, S>, Option<&'a mut S>, u64, SZ, SZ)>,
pub type CmpExecHook<ET, I, S, SZ> = Hook<
fn(&mut EmulatorModules<ET, I, S>, Option<&mut S>, id: u64, v0: SZ, v1: SZ),
Box<dyn for<'a> FnMut(&'a mut EmulatorModules<ET, I, S>, Option<&'a mut S>, u64, SZ, SZ)>,
unsafe extern "C" fn(*const (), id: u64, v0: SZ, v1: SZ),
>;
create_hook_id!(Cmp, libafl_qemu_remove_cmp_hook, true);
@ -843,9 +878,9 @@ create_exec_wrapper!(cmp, (id: u64, v0: u64, v1: u64), 3, 4, CmpHookId);
// Crash hook wrappers
#[cfg(feature = "usermode")]
pub type CrashHookFn<ET, S> = fn(Qemu, &mut EmulatorModules<ET, S>, i32);
pub type CrashHookFn<ET, I, S> = fn(Qemu, &mut EmulatorModules<ET, I, S>, i32);
#[cfg(feature = "usermode")]
pub type CrashHookClosure<ET, S> = Box<dyn FnMut(Qemu, &mut EmulatorModules<ET, S>, i32)>;
pub type CrashHookClosure<ET, I, S> = Box<dyn FnMut(Qemu, &mut EmulatorModules<ET, I, S>, i32)>;
/// The thin wrapper around QEMU hooks.
/// It is considered unsafe to use it directly.

View File

@ -1,9 +1,8 @@
use std::fmt::{Debug, Formatter};
use std::fmt::Debug;
use enum_map::Enum;
use libafl::inputs::UsesInput;
use crate::{command::CommandManager, get_exit_arch_regs, GuestReg, Regs, CPU};
use crate::{get_exit_arch_regs, GuestReg, Regs, CPU};
#[derive(Debug, Clone, Enum)]
pub enum ExitArgs {
@ -17,48 +16,19 @@ pub enum ExitArgs {
Arg6,
}
pub struct CustomInsn<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
command: CM::Commands,
#[derive(Clone, Debug)]
pub struct CustomInsn<C> {
command: C,
}
impl<CM, ED, ET, S, SM> Clone for CustomInsn<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
fn clone(&self) -> Self {
Self {
command: self.command.clone(),
}
}
}
impl<CM, ED, ET, S, SM> Debug for CustomInsn<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Sync Exit")
}
}
impl<CM, ED, ET, S, SM> CustomInsn<CM, ED, ET, S, SM>
where
CM: CommandManager<ED, ET, S, SM>,
S: UsesInput,
{
impl<C> CustomInsn<C> {
#[must_use]
pub fn new(command: CM::Commands) -> Self {
pub fn new(command: C) -> Self {
Self { command }
}
#[must_use]
pub fn command(&self) -> &CM::Commands {
pub fn command(&self) -> &C {
&self.command
}

View File

@ -231,7 +231,7 @@ where
}
};
let mut harness = |_emulator: &mut Emulator<_, _, _, _, _>,
let mut harness = |_emulator: &mut Emulator<_, _, _, _, _, _, _>,
_state: &mut _,
input: &BytesInput| {
let target = input.target_bytes();
@ -352,7 +352,7 @@ where
.build()
.unwrap());
let mut harness = |_emulator: &mut Emulator<_, _, _, _, _>,
let mut harness = |_emulator: &mut Emulator<_, _, _, _, _, _, _>,
_state: &mut _,
input: &BytesInput| {
let target = input.target_bytes();

View File

@ -30,20 +30,20 @@ extern "C" {
///
/// # Safety
/// Calls the unsafe `__sanitizer_set_death_callback` symbol, but should be safe to call otherwise.
pub unsafe fn setup_asan_callback<E, EM, OF, S, Z>(_executor: &E, _event_mgr: &EM, _fuzzer: &Z)
pub unsafe fn setup_asan_callback<E, EM, I, OF, S, Z>(_executor: &E, _event_mgr: &EM, _fuzzer: &Z)
where
E: Executor<EM, <S::Corpus as Corpus>::Input, S, Z> + HasObservers,
E::Observers: ObserversTuple<<S::Corpus as Corpus>::Input, S>,
E: Executor<EM, I, S, Z> + HasObservers,
E::Observers: ObserversTuple<I, S>,
EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<EM, <S::Corpus as Corpus>::Input, E::Observers, S>,
OF: Feedback<EM, I, E::Observers, S>,
S: HasExecutions
+ HasSolutions
+ HasCurrentTestcase
+ HasCorpus
+ UsesInput<Input = <S::Corpus as Corpus>::Input>,
S::Solutions: Corpus<Input = <S::Corpus as Corpus>::Input>,
+ UsesInput<Input = I>,
S::Solutions: Corpus<Input = I>,
Z: HasObjective<Objective = OF>,
<S::Corpus as Corpus>::Input: Input + Clone,
I: Input + Clone,
{
__sanitizer_set_death_callback(Some(asan_death_handler::<E, EM, OF, S, Z>));
__sanitizer_set_death_callback(Some(asan_death_handler::<E, EM, I, OF, S, Z>));
}