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:
parent
8adb2aa7b5
commit
a45e44764f
4
.github/workflows/build_and_test.yml
vendored
4
.github/workflows/build_and_test.yml
vendored
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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),
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
||||
|
@ -87,10 +87,11 @@ 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 {
|
||||
emulator.run(state, input).unwrap().try_into().unwrap()
|
||||
};
|
||||
let mut harness = |emulator: &mut Emulator<_, _, _, _, _, _, _>,
|
||||
state: &mut _,
|
||||
input: &BytesInput| unsafe {
|
||||
emulator.run(state, input).unwrap().try_into().unwrap()
|
||||
};
|
||||
|
||||
// Create an observation channel using the coverage map
|
||||
let mut edges_observer = unsafe {
|
||||
|
@ -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();
|
||||
|
@ -71,10 +71,11 @@ 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 {
|
||||
emulator.run(state, input).unwrap().try_into().unwrap()
|
||||
};
|
||||
let mut harness = |emulator: &mut Emulator<_, _, _, _, _, _, _>,
|
||||
state: &mut _,
|
||||
input: &BytesInput| unsafe {
|
||||
emulator.run(state, input).unwrap().try_into().unwrap()
|
||||
};
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
|
@ -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"
|
||||
|
@ -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,10 +149,11 @@ 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 {
|
||||
emulator.run(state, input).unwrap().try_into().unwrap()
|
||||
};
|
||||
let mut harness = |emulator: &mut Emulator<_, _, _, _, _, _, _>,
|
||||
state: &mut _,
|
||||
input: &BytesInput| unsafe {
|
||||
emulator.run(state, input).unwrap().try_into().unwrap()
|
||||
};
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! A systemmode linux kernel example
|
||||
//!
|
||||
#[cfg(all(target_os = "linux"))]
|
||||
#[cfg(target_os = "linux")]
|
||||
mod fuzzer;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
|
@ -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"
|
||||
|
@ -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,15 +147,16 @@ 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 {
|
||||
match emulator.run(state, input) {
|
||||
Ok(res) => res.try_into().unwrap(),
|
||||
Err(e) => match e {
|
||||
_ => panic!("{e:?}"),
|
||||
},
|
||||
}
|
||||
};
|
||||
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 {
|
||||
_ => panic!("{e:?}"),
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! A systemmode linux kernel example
|
||||
//!
|
||||
#[cfg(all(target_os = "linux"))]
|
||||
#[cfg(target_os = "linux")]
|
||||
mod fuzzer;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
|
@ -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))]
|
||||
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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))
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
{
|
||||
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.
|
||||
Timeout, // Timeout
|
||||
#[derive(Clone)]
|
||||
pub enum EmulatorExitResult<C> {
|
||||
QemuExit(QemuShutdownCause), // QEMU ended for some reason.
|
||||
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);
|
||||
}
|
||||
|
@ -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]) {
|
||||
|
@ -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 {
|
||||
|
@ -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,18 +180,25 @@ 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| {
|
||||
eprintln!("Crashed with signal {host_sig}");
|
||||
unsafe {
|
||||
libafl::executors::inprocess::generic_inproc_crash_handler::<Self, EM, OF, S, Z>(
|
||||
);
|
||||
}
|
||||
if let Some(cpu) = qemu.current_cpu() {
|
||||
eprint!("Context:\n{}", cpu.display_context());
|
||||
}
|
||||
};
|
||||
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,
|
||||
I,
|
||||
OF,
|
||||
S,
|
||||
Z,
|
||||
>();
|
||||
}
|
||||
if let Some(cpu) = qemu.current_cpu() {
|
||||
eprint!("Context:\n{}", cpu.display_context());
|
||||
}
|
||||
};
|
||||
|
||||
// # Safety
|
||||
// We assume our crash handlers to be safe/quit after execution.
|
||||
@ -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,
|
||||
{
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
);
|
||||
|
@ -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);
|
||||
|
@ -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),
|
||||
);
|
||||
}
|
||||
|
@ -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),
|
||||
);
|
||||
|
@ -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),
|
||||
);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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>),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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>));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user