Abort on triple fault for in process executors, refactor AddressFilter and PageFilter (#3026)

* abort on triple fault in generic inprocess signal handler

* refactor qemu filters

---------

Co-authored-by: Toka <tokazerkje@outlook.com>
This commit is contained in:
Romain Malmain 2025-02-28 15:44:22 +01:00 committed by GitHub
parent 191bc6d12d
commit e864bc28b1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 393 additions and 263 deletions

View File

@ -120,6 +120,10 @@ jobs:
# ---- build normal and examples ---- # ---- build normal and examples ----
- name: Run a normal build - name: Run a normal build
run: cargo build --verbose run: cargo build --verbose
- name: Run libafl_qemu usermode tests
run: cd libafl_qemu && cargo test
- name: Run libafl_qemu systemmode tests
run: cd libafl_qemu && cargo test --no-default-features --features x86_64,systemmode
- name: Build examples - name: Build examples
run: cargo build --examples --verbose run: cargo build --examples --verbose

8
.gitignore vendored
View File

@ -78,4 +78,10 @@ fuzzer_libpng*
*.patch *.patch
# Sometimes this happens # Sometimes this happens
rustc-ice-* rustc-ice-*
# perf files
*.mm_profdata
# backup files
*.bak

View File

@ -41,7 +41,7 @@ use libafl_qemu::{
executor::QemuExecutor, executor::QemuExecutor,
modules::{ modules::{
cmplog::CmpLogObserver, edges::StdEdgeCoverageClassicModule, cmplog::CmpLogObserver, edges::StdEdgeCoverageClassicModule,
utils::filters::HasAddressFilterTuples, CmpLogModule, EmulatorModuleTuple, utils::filters::HasAddressFilterTuple, CmpLogModule, EmulatorModuleTuple,
}, },
FastSnapshotManager, NopSnapshotManager, QemuInitError, FastSnapshotManager, NopSnapshotManager, QemuInitError,
}; };
@ -78,12 +78,12 @@ fn get_emulator<C, ET, I, S>(
QemuInitError, QemuInitError,
> >
where where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples, ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuple,
I: HasTargetBytes + Unpin, I: HasTargetBytes + Unpin,
S: HasExecutions + Unpin, S: HasExecutions + Unpin,
{ {
// Allow linux process address space addresses as feedback // Allow linux process address space addresses as feedback
modules.allow_address_range_all(LINUX_PROCESS_ADDRESS_RANGE); modules.allow_address_range_all(&LINUX_PROCESS_ADDRESS_RANGE);
Emulator::builder() Emulator::builder()
.qemu_parameters(args) .qemu_parameters(args)

View File

@ -41,7 +41,7 @@ use libafl_qemu::{
executor::QemuExecutor, executor::QemuExecutor,
modules::{ modules::{
cmplog::CmpLogObserver, edges::StdEdgeCoverageClassicModule, cmplog::CmpLogObserver, edges::StdEdgeCoverageClassicModule,
utils::filters::HasAddressFilterTuples, CmpLogModule, EmulatorModuleTuple, utils::filters::HasAddressFilterTuple, CmpLogModule, EmulatorModuleTuple,
}, },
FastSnapshotManager, NopSnapshotManager, QemuInitError, QemuSnapshotManager, FastSnapshotManager, NopSnapshotManager, QemuInitError, QemuSnapshotManager,
}; };
@ -78,12 +78,12 @@ fn get_emulator<C, ET, I, S>(
QemuInitError, QemuInitError,
> >
where where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples, ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuple,
I: HasTargetBytes + Unpin, I: HasTargetBytes + Unpin,
S: HasExecutions + Unpin, S: HasExecutions + Unpin,
{ {
// Allow linux process address space addresses as feedback // Allow linux process address space addresses as feedback
modules.allow_address_range_all(LINUX_PROCESS_ADDRESS_RANGE); modules.allow_address_range_all(&LINUX_PROCESS_ADDRESS_RANGE);
Emulator::builder() Emulator::builder()
.qemu_parameters(args) .qemu_parameters(args)

View File

@ -8,10 +8,10 @@ use core::{fmt::Debug, marker::PhantomData, time::Duration};
use libafl_bolts::ClientId; use libafl_bolts::ClientId;
#[cfg(all(feature = "std", any(windows, not(feature = "fork"))))] #[cfg(all(feature = "std", any(windows, not(feature = "fork"))))]
use libafl_bolts::os::startable_self; use libafl_bolts::os::startable_self;
#[cfg(all(unix, feature = "std", not(miri)))]
use libafl_bolts::os::unix_signals::setup_signal_handler;
#[cfg(all(feature = "std", feature = "fork", unix))] #[cfg(all(feature = "std", feature = "fork", unix))]
use libafl_bolts::os::{ForkResult, fork}; use libafl_bolts::os::{ForkResult, fork};
#[cfg(all(unix, feature = "std", not(miri)))]
use libafl_bolts::os::{SIGNAL_RECURSION_EXIT, unix_signals::setup_signal_handler};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use libafl_bolts::{ use libafl_bolts::{
os::CTRL_C_EXIT, os::CTRL_C_EXIT,
@ -510,6 +510,13 @@ where
return Err(Error::shutting_down()); return Err(Error::shutting_down());
} }
#[cfg(all(unix, feature = "std"))]
if child_status == SIGNAL_RECURSION_EXIT {
return Err(Error::illegal_state(
"The client is stuck in an unexpected signal handler recursion. It is most likely a fuzzer bug.",
));
}
#[expect(clippy::manual_assert)] #[expect(clippy::manual_assert)]
if !staterestorer.has_content() { if !staterestorer.has_content() {
#[cfg(unix)] #[cfg(unix)]

View File

@ -355,7 +355,9 @@ pub struct InProcessExecutorHandlerData {
/// the pointer to the executor /// the pointer to the executor
pub executor_ptr: *const c_void, pub executor_ptr: *const c_void,
pub(crate) current_input_ptr: *const c_void, pub(crate) current_input_ptr: *const c_void,
pub(crate) in_handler: bool,
#[cfg(feature = "std")]
pub(crate) signal_handler_depth: usize,
/// The timeout handler /// The timeout handler
#[cfg(feature = "std")] #[cfg(feature = "std")]
@ -376,6 +378,9 @@ unsafe impl Send for InProcessExecutorHandlerData {}
unsafe impl Sync for InProcessExecutorHandlerData {} unsafe impl Sync for InProcessExecutorHandlerData {}
impl InProcessExecutorHandlerData { impl InProcessExecutorHandlerData {
#[cfg(feature = "std")]
const SIGNAL_HANDLER_MAX_DEPTH: usize = 3;
/// # Safety /// # Safety
/// Only safe if not called twice and if the executor is not used from another borrow after this. /// Only safe if not called twice and if the executor is not used from another borrow after this.
#[cfg(all(feature = "std", any(unix, windows)))] #[cfg(all(feature = "std", any(unix, windows)))]
@ -418,11 +423,19 @@ impl InProcessExecutorHandlerData {
!self.current_input_ptr.is_null() !self.current_input_ptr.is_null()
} }
/// Returns true if signal handling max depth has been reached, false otherwise
#[cfg(all(feature = "std", any(unix, windows)))] #[cfg(all(feature = "std", any(unix, windows)))]
pub(crate) fn set_in_handler(&mut self, v: bool) -> bool { pub(crate) fn signal_handler_enter(&mut self) -> (bool, usize) {
let old = self.in_handler; self.signal_handler_depth += 1;
self.in_handler = v; (
old self.signal_handler_depth >= Self::SIGNAL_HANDLER_MAX_DEPTH,
self.signal_handler_depth,
)
}
#[cfg(all(feature = "std", any(unix, windows)))]
pub(crate) fn signal_handler_exit(&mut self) {
self.signal_handler_depth -= 1;
} }
/// if data is valid, safely report a crash and return true. /// if data is valid, safely report a crash and return true.
@ -500,7 +513,8 @@ pub static mut GLOBAL_STATE: InProcessExecutorHandlerData = InProcessExecutorHan
// The current input for signal handling // The current input for signal handling
current_input_ptr: ptr::null(), current_input_ptr: ptr::null(),
in_handler: false, #[cfg(feature = "std")]
signal_handler_depth: 0,
// The crash handler fn // The crash handler fn
#[cfg(feature = "std")] #[cfg(feature = "std")]
@ -560,11 +574,3 @@ pub unsafe fn inprocess_get_executor<'a, E>() -> Option<&'a mut E> {
pub unsafe fn inprocess_get_input<'a, I>() -> Option<&'a I> { pub unsafe fn inprocess_get_input<'a, I>() -> Option<&'a I> {
unsafe { (GLOBAL_STATE.current_input_ptr as *const I).as_ref() } unsafe { (GLOBAL_STATE.current_input_ptr as *const I).as_ref() }
} }
/// Returns if we are executing in a crash/timeout handler
#[must_use]
pub fn inprocess_in_handler() -> bool {
// # Safety
// Safe because the state is set up and the handler is a single bool. Worst case we read an old value.
unsafe { GLOBAL_STATE.in_handler }
}

View File

@ -2,7 +2,7 @@
//! These will be executed right before and after the executor's harness run. //! These will be executed right before and after the executor's harness run.
/// windows crash/timeout handler and asan death callback /// windows crash/timeout handler and asan death callback
#[cfg(windows)] #[cfg(all(windows, feature = "std"))]
pub mod windows; pub mod windows;
/// *nix crash handler /// *nix crash handler

View File

@ -5,7 +5,10 @@ pub mod unix_signal_handler {
use core::mem::transmute; use core::mem::transmute;
use std::{io::Write, panic}; use std::{io::Write, panic};
use libafl_bolts::os::unix_signals::{Signal, SignalHandler, ucontext_t}; use libafl_bolts::os::{
SIGNAL_RECURSION_EXIT,
unix_signals::{Signal, SignalHandler, ucontext_t},
};
use libc::siginfo_t; use libc::siginfo_t;
use crate::{ use crate::{
@ -50,11 +53,13 @@ pub mod unix_signal_handler {
) { ) {
unsafe { unsafe {
let data = &raw mut GLOBAL_STATE; let data = &raw mut GLOBAL_STATE;
let in_handler = (*data).set_in_handler(true); let (max_depth_reached, signal_depth) = (*data).signal_handler_enter();
if in_handler { if max_depth_reached {
log::error!("We crashed inside a crash handler, but this should never happen!"); log::error!(
libc::exit(56); "The in process signal handler has been triggered {signal_depth} times recursively, which is not expected. Exiting with error code {SIGNAL_RECURSION_EXIT}..."
);
libc::exit(SIGNAL_RECURSION_EXIT);
} }
match signal { match signal {
@ -67,11 +72,11 @@ pub mod unix_signal_handler {
_ => { _ => {
if !(*data).crash_handler.is_null() { if !(*data).crash_handler.is_null() {
let func: HandlerFuncPtr = transmute((*data).crash_handler); let func: HandlerFuncPtr = transmute((*data).crash_handler);
(func)(signal, info, context, data); func(signal, info, context, data);
} }
} }
} }
(*data).set_in_handler(in_handler); (*data).signal_handler_exit();
} }
} }
@ -95,11 +100,13 @@ pub mod unix_signal_handler {
panic::set_hook(Box::new(move |panic_info| unsafe { panic::set_hook(Box::new(move |panic_info| unsafe {
old_hook(panic_info); old_hook(panic_info);
let data = &raw mut GLOBAL_STATE; let data = &raw mut GLOBAL_STATE;
let in_handler = (*data).set_in_handler(true); let (max_depth_reached, signal_depth) = (*data).signal_handler_enter();
if in_handler { if max_depth_reached {
log::error!("We crashed inside a crash panic hook, but this should never happen!"); log::error!(
libc::exit(56); "The in process signal handler has been triggered {signal_depth} times recursively, which is not expected. Exiting with error code {SIGNAL_RECURSION_EXIT}..."
);
libc::exit(SIGNAL_RECURSION_EXIT);
} }
if (*data).is_valid() { if (*data).is_valid() {
@ -121,7 +128,8 @@ pub mod unix_signal_handler {
libc::_exit(128 + 6); // SIGABRT exit code libc::_exit(128 + 6); // SIGABRT exit code
} }
(*data).set_in_handler(in_handler);
(*data).signal_handler_exit();
})); }));
} }

View File

@ -1,9 +1,9 @@
/// In-Process crash handling for `Windows` /// In-Process crash handling for `Windows`
#[cfg(all(windows, feature = "std"))]
pub mod windows_asan_handler { pub mod windows_asan_handler {
use alloc::string::String; use alloc::string::String;
use core::sync::atomic::{Ordering, compiler_fence}; use core::sync::atomic::{Ordering, compiler_fence};
use libafl_bolts::os::SIGNAL_RECURSION_EXIT;
use windows::Win32::System::Threading::{ use windows::Win32::System::Threading::{
CRITICAL_SECTION, EnterCriticalSection, ExitProcess, LeaveCriticalSection, CRITICAL_SECTION, EnterCriticalSection, ExitProcess, LeaveCriticalSection,
}; };
@ -35,13 +35,13 @@ pub mod windows_asan_handler {
{ {
unsafe { unsafe {
let data = &raw mut GLOBAL_STATE; let data = &raw mut GLOBAL_STATE;
let in_handler = (*data).set_in_handler(true); let (max_depth_reached, _signal_depth) = (*data).signal_handler_enter();
if in_handler { if max_depth_reached {
log::error!( log::error!(
"We crashed inside a asan death handler, but this should never happen!" "We crashed inside a asan death handler, but this should never happen!"
); );
ExitProcess(56); ExitProcess(SIGNAL_RECURSION_EXIT as u32);
} }
// Have we set a timer_before? // Have we set a timer_before?
@ -109,7 +109,6 @@ pub mod windows_asan_handler {
} }
} }
#[cfg(all(windows, feature = "std"))]
/// The module to take care of windows crash or timeouts /// The module to take care of windows crash or timeouts
pub mod windows_exception_handler { pub mod windows_exception_handler {
#[cfg(feature = "std")] #[cfg(feature = "std")]
@ -126,9 +125,12 @@ pub mod windows_exception_handler {
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::panic; use std::panic;
use libafl_bolts::os::windows_exceptions::{ use libafl_bolts::os::{
CRASH_EXCEPTIONS, EXCEPTION_HANDLERS_SIZE, EXCEPTION_POINTERS, ExceptionCode, SIGNAL_RECURSION_EXIT,
ExceptionHandler, windows_exceptions::{
CRASH_EXCEPTIONS, EXCEPTION_HANDLERS_SIZE, EXCEPTION_POINTERS, ExceptionCode,
ExceptionHandler,
},
}; };
use windows::Win32::System::Threading::{ use windows::Win32::System::Threading::{
CRITICAL_SECTION, EnterCriticalSection, ExitProcess, LeaveCriticalSection, CRITICAL_SECTION, EnterCriticalSection, ExitProcess, LeaveCriticalSection,
@ -168,18 +170,18 @@ pub mod windows_exception_handler {
) { ) {
unsafe { unsafe {
let data = &raw mut GLOBAL_STATE; let data = &raw mut GLOBAL_STATE;
let in_handler = (*data).set_in_handler(true); let (max_depth_reached, _signal_depth) = (*data).signal_handler_enter();
if in_handler { if max_depth_reached {
log::error!("We crashed inside a crash handler, but this should never happen!"); log::error!("We crashed inside a crash handler, but this should never happen!");
ExitProcess(56); ExitProcess(SIGNAL_RECURSION_EXIT as u32);
} }
if !(*data).crash_handler.is_null() { if !(*data).crash_handler.is_null() {
let func: HandlerFuncPtr = transmute((*data).crash_handler); let func: HandlerFuncPtr = transmute((*data).crash_handler);
(func)(exception_pointers, data); (func)(exception_pointers, data);
} }
(*data).set_in_handler(in_handler); (*data).signal_handler_exit();
} }
} }
@ -208,11 +210,11 @@ pub mod windows_exception_handler {
let old_hook = panic::take_hook(); let old_hook = panic::take_hook();
panic::set_hook(Box::new(move |panic_info| unsafe { panic::set_hook(Box::new(move |panic_info| unsafe {
let data = &raw mut GLOBAL_STATE; let data = &raw mut GLOBAL_STATE;
let in_handler = (*data).set_in_handler(true); let (max_depth_reached, _signal_depth) = (*data).signal_handler_enter();
if in_handler { if max_depth_reached {
log::error!("We crashed inside a crash handler, but this should never happen!"); log::error!("We crashed inside a crash handler, but this should never happen!");
ExitProcess(56); ExitProcess(SIGNAL_RECURSION_EXIT as u32);
} }
// Have we set a timer_before? // Have we set a timer_before?
@ -252,7 +254,7 @@ pub mod windows_exception_handler {
ExitProcess(1); ExitProcess(1);
} }
old_hook(panic_info); old_hook(panic_info);
(*data).set_in_handler(in_handler); (*data).signal_handler_exit();
})); }));
} }

View File

@ -48,6 +48,9 @@ pub struct ChildHandle {
pub pid: pid_t, pub pid: pid_t,
} }
/// The special exit code when the target signal handler is crashing recursively
pub const SIGNAL_RECURSION_EXIT: i32 = 101;
#[cfg(unix)] #[cfg(unix)]
impl ChildHandle { impl ChildHandle {
/// Block until the child exited and the status code becomes available /// Block until the child exited and the status code becomes available

View File

@ -25,7 +25,7 @@ use crate::{
VersionCommandParser, VersionCommandParser,
}, },
get_exit_arch_regs, get_exit_arch_regs,
modules::{EmulatorModuleTuple, utils::filters::HasAddressFilterTuples}, modules::{EmulatorModuleTuple, utils::filters::HasStdFiltersTuple},
sync_exit::ExitArgs, sync_exit::ExitArgs,
}; };
@ -96,7 +96,7 @@ macro_rules! define_std_command_manager {
impl<C, ET, I, S, SM> CommandManager<C, StdEmulatorDriver, ET, I, S, SM> for $name<S> impl<C, ET, I, S, SM> CommandManager<C, StdEmulatorDriver, ET, I, S, SM> for $name<S>
where where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples, ET: EmulatorModuleTuple<I, S> + HasStdFiltersTuple,
I: HasTargetBytes + Unpin, I: HasTargetBytes + Unpin,
S: Unpin, S: Unpin,
SM: IsSnapshotManager, SM: IsSnapshotManager,
@ -125,7 +125,7 @@ macro_rules! define_std_command_manager {
impl<C, ET, I, S, SM> IsCommand<C, $name<S>, StdEmulatorDriver, ET, I, S, SM> for [<$name Commands>] impl<C, ET, I, S, SM> IsCommand<C, $name<S>, StdEmulatorDriver, ET, I, S, SM> for [<$name Commands>]
where where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples, ET: EmulatorModuleTuple<I, S> + HasStdFiltersTuple,
I: HasTargetBytes + Unpin, I: HasTargetBytes + Unpin,
S: Unpin, S: Unpin,
SM: IsSnapshotManager, SM: IsSnapshotManager,
@ -383,7 +383,7 @@ pub struct StartCommand {
impl<C, ET, I, S, SM> IsCommand<C, StdCommandManager<S>, StdEmulatorDriver, ET, I, S, SM> impl<C, ET, I, S, SM> IsCommand<C, StdCommandManager<S>, StdEmulatorDriver, ET, I, S, SM>
for StartCommand for StartCommand
where where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples, ET: EmulatorModuleTuple<I, S> + HasStdFiltersTuple,
I: HasTargetBytes + Unpin, I: HasTargetBytes + Unpin,
S: Unpin, S: Unpin,
SM: IsSnapshotManager, SM: IsSnapshotManager,
@ -544,7 +544,7 @@ pub struct PageAllowCommand {
#[cfg(feature = "systemmode")] #[cfg(feature = "systemmode")]
impl<C, CM, ED, ET, I, S, SM> IsCommand<C, CM, ED, ET, I, S, SM> for PageAllowCommand impl<C, CM, ED, ET, I, S, SM> IsCommand<C, CM, ED, ET, I, S, SM> for PageAllowCommand
where where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples, ET: EmulatorModuleTuple<I, S> + HasStdFiltersTuple,
I: Unpin, I: Unpin,
S: Unpin, S: Unpin,
{ {
@ -572,7 +572,7 @@ pub struct AddressAllowCommand {
} }
impl<C, CM, ED, ET, I, S, SM> IsCommand<C, CM, ED, ET, I, S, SM> for AddressAllowCommand impl<C, CM, ED, ET, I, S, SM> IsCommand<C, CM, ED, ET, I, S, SM> for AddressAllowCommand
where where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples, ET: EmulatorModuleTuple<I, S> + HasStdFiltersTuple,
I: Unpin, I: Unpin,
S: Unpin, S: Unpin,
{ {
@ -589,7 +589,7 @@ where
) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> { ) -> Result<Option<EmulatorDriverResult<C>>, EmulatorDriverError> {
emu.modules_mut() emu.modules_mut()
.modules_mut() .modules_mut()
.allow_address_range_all(self.address_range.clone()); .allow_address_range_all(&self.address_range);
Ok(None) Ok(None)
} }
} }

View File

@ -34,7 +34,7 @@ use crate::{
}, },
}, },
get_exit_arch_regs, get_exit_arch_regs,
modules::{EmulatorModuleTuple, utils::filters::HasAddressFilterTuples}, modules::{EmulatorModuleTuple, utils::filters::HasStdFiltersTuple},
sync_exit::ExitArgs, sync_exit::ExitArgs,
}; };
@ -99,7 +99,7 @@ macro_rules! define_nyx_command_manager {
impl<C, ET, I, S, SM> CommandManager<C, NyxEmulatorDriver, ET, I, S, SM> for $name<S> impl<C, ET, I, S, SM> CommandManager<C, NyxEmulatorDriver, ET, I, S, SM> for $name<S>
where where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples, ET: EmulatorModuleTuple<I, S> + HasStdFiltersTuple,
I: HasTargetBytes + Unpin, I: HasTargetBytes + Unpin,
S: Unpin, S: Unpin,
SM: IsSnapshotManager, SM: IsSnapshotManager,
@ -134,7 +134,7 @@ macro_rules! define_nyx_command_manager {
impl<C, ET, I, S, SM> IsCommand<C, $name<S>, NyxEmulatorDriver, ET, I, S, SM> for [<$name Commands>] impl<C, ET, I, S, SM> IsCommand<C, $name<S>, NyxEmulatorDriver, ET, I, S, SM> for [<$name Commands>]
where where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples, ET: EmulatorModuleTuple<I, S> + HasStdFiltersTuple,
I: HasTargetBytes + Unpin, I: HasTargetBytes + Unpin,
S: Unpin, S: Unpin,
SM: IsSnapshotManager, SM: IsSnapshotManager,
@ -296,7 +296,7 @@ pub struct NextPayloadCommand;
impl<C, ET, I, S, SM> IsCommand<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM> impl<C, ET, I, S, SM> IsCommand<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for NextPayloadCommand for NextPayloadCommand
where where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples, ET: EmulatorModuleTuple<I, S> + HasStdFiltersTuple,
I: HasTargetBytes + Unpin, I: HasTargetBytes + Unpin,
S: Unpin, S: Unpin,
SM: IsSnapshotManager, SM: IsSnapshotManager,
@ -360,7 +360,7 @@ pub struct SubmitCR3Command;
impl<C, ET, I, S, SM> IsCommand<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM> impl<C, ET, I, S, SM> IsCommand<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for SubmitCR3Command for SubmitCR3Command
where where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples, ET: EmulatorModuleTuple<I, S> + HasStdFiltersTuple,
I: HasTargetBytes + Unpin, I: HasTargetBytes + Unpin,
S: Unpin, S: Unpin,
SM: IsSnapshotManager, SM: IsSnapshotManager,
@ -408,7 +408,7 @@ impl RangeSubmitCommand {
impl<C, ET, I, S, SM> IsCommand<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM> impl<C, ET, I, S, SM> IsCommand<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for RangeSubmitCommand for RangeSubmitCommand
where where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples, ET: EmulatorModuleTuple<I, S> + HasStdFiltersTuple,
I: HasTargetBytes + Unpin, I: HasTargetBytes + Unpin,
S: Unpin, S: Unpin,
SM: IsSnapshotManager, SM: IsSnapshotManager,
@ -440,7 +440,7 @@ where
emu.modules_mut() emu.modules_mut()
.modules_mut() .modules_mut()
.allow_address_range_all(self.allowed_range.clone()); .allow_address_range_all(&self.allowed_range);
Ok(None) Ok(None)
} }
} }

View File

@ -12,7 +12,7 @@ use crate::{
LoadCommand, LqprintfCommand, NativeExitKind, SaveCommand, StartCommand, StdCommandManager, LoadCommand, LqprintfCommand, NativeExitKind, SaveCommand, StartCommand, StdCommandManager,
TestCommand, VersionCommand, bindings, TestCommand, VersionCommand, bindings,
}, },
modules::{EmulatorModuleTuple, utils::filters::HasAddressFilterTuples}, modules::{EmulatorModuleTuple, utils::filters::HasStdFiltersTuple},
sync_exit::ExitArgs, sync_exit::ExitArgs,
}; };
@ -92,7 +92,7 @@ pub struct StartPhysCommandParser;
impl<C, ET, I, S, SM> NativeCommandParser<C, StdCommandManager<S>, StdEmulatorDriver, ET, I, S, SM> impl<C, ET, I, S, SM> NativeCommandParser<C, StdCommandManager<S>, StdEmulatorDriver, ET, I, S, SM>
for StartPhysCommandParser for StartPhysCommandParser
where where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples, ET: EmulatorModuleTuple<I, S> + HasStdFiltersTuple,
I: HasTargetBytes + Unpin, I: HasTargetBytes + Unpin,
S: Unpin, S: Unpin,
SM: IsSnapshotManager, SM: IsSnapshotManager,
@ -121,7 +121,7 @@ pub struct StartVirtCommandParser;
impl<C, ET, I, S, SM> NativeCommandParser<C, StdCommandManager<S>, StdEmulatorDriver, ET, I, S, SM> impl<C, ET, I, S, SM> NativeCommandParser<C, StdCommandManager<S>, StdEmulatorDriver, ET, I, S, SM>
for StartVirtCommandParser for StartVirtCommandParser
where where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples, ET: EmulatorModuleTuple<I, S> + HasStdFiltersTuple,
I: HasTargetBytes + Unpin, I: HasTargetBytes + Unpin,
S: Unpin, S: Unpin,
SM: IsSnapshotManager, SM: IsSnapshotManager,
@ -242,7 +242,7 @@ pub struct VaddrFilterAllowRangeCommandParser;
impl<C, CM, ED, ET, I, S, SM> NativeCommandParser<C, CM, ED, ET, I, S, SM> impl<C, CM, ED, ET, I, S, SM> NativeCommandParser<C, CM, ED, ET, I, S, SM>
for VaddrFilterAllowRangeCommandParser for VaddrFilterAllowRangeCommandParser
where where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples, ET: EmulatorModuleTuple<I, S> + HasStdFiltersTuple,
I: Unpin, I: Unpin,
S: Unpin, S: Unpin,
{ {

View File

@ -17,7 +17,7 @@ use crate::{
}, },
parser::NativeCommandParser, parser::NativeCommandParser,
}, },
modules::{EmulatorModuleTuple, utils::filters::HasAddressFilterTuples}, modules::{EmulatorModuleTuple, utils::filters::HasStdFiltersTuple},
sync_exit::ExitArgs, sync_exit::ExitArgs,
}; };
@ -81,7 +81,7 @@ pub struct SubmitCR3CommandParser;
impl<C, ET, I, S, SM> NativeCommandParser<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM> impl<C, ET, I, S, SM> NativeCommandParser<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for SubmitCR3CommandParser for SubmitCR3CommandParser
where where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples, ET: EmulatorModuleTuple<I, S> + HasStdFiltersTuple,
I: HasTargetBytes + Unpin, I: HasTargetBytes + Unpin,
S: Unpin, S: Unpin,
SM: IsSnapshotManager, SM: IsSnapshotManager,
@ -101,7 +101,7 @@ pub struct RangeSubmitCommandParser;
impl<C, ET, I, S, SM> NativeCommandParser<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM> impl<C, ET, I, S, SM> NativeCommandParser<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for RangeSubmitCommandParser for RangeSubmitCommandParser
where where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples, ET: EmulatorModuleTuple<I, S> + HasStdFiltersTuple,
I: HasTargetBytes + Unpin, I: HasTargetBytes + Unpin,
S: Unpin, S: Unpin,
SM: IsSnapshotManager, SM: IsSnapshotManager,
@ -189,7 +189,7 @@ pub struct NextPayloadCommandParser;
impl<C, ET, I, S, SM> NativeCommandParser<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM> impl<C, ET, I, S, SM> NativeCommandParser<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for NextPayloadCommandParser for NextPayloadCommandParser
where where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples, ET: EmulatorModuleTuple<I, S> + HasStdFiltersTuple,
I: HasTargetBytes + Unpin, I: HasTargetBytes + Unpin,
S: Unpin, S: Unpin,
SM: IsSnapshotManager, SM: IsSnapshotManager,

View File

@ -12,7 +12,7 @@ use thread_local::ThreadLocal;
use super::utils::filters::HasAddressFilter; use super::utils::filters::HasAddressFilter;
#[cfg(feature = "systemmode")] #[cfg(feature = "systemmode")]
use crate::modules::utils::filters::{NOP_PAGE_FILTER, NopPageFilter}; use crate::modules::utils::filters::{HasPageFilter, NOP_PAGE_FILTER, NopPageFilter};
use crate::{ use crate::{
Qemu, capstone, Qemu, capstone,
modules::{ modules::{
@ -361,14 +361,18 @@ where
iaddr += insn.bytes().len() as GuestAddr; iaddr += insn.bytes().len() as GuestAddr;
#[cfg(feature = "usermode")] #[cfg(feature = "usermode")]
code = unsafe { std::slice::from_raw_parts(qemu.g2h(iaddr), 512) }; {
code = unsafe { std::slice::from_raw_parts(qemu.g2h(iaddr), 512) };
}
#[cfg(feature = "systemmode")] #[cfg(feature = "systemmode")]
if let Err(err) = qemu.read_mem(pc, code) { {
// TODO handle faults if let Err(err) = qemu.read_mem(pc, code) {
log::error!( // TODO handle faults
"gen_block_calls error 2: Failed to read mem at pc {pc:#x}: {err:?}" log::error!(
); "gen_block_calls error 2: Failed to read mem at pc {pc:#x}: {err:?}"
return None; );
return None;
}
} }
} }
} }
@ -459,24 +463,29 @@ impl<T> HasAddressFilter for CallTracerModule<T>
where where
T: CallTraceCollectorTuple, T: CallTraceCollectorTuple,
{ {
type ModuleAddressFilter = StdAddressFilter; type AddressFilter = StdAddressFilter;
#[cfg(feature = "systemmode")]
type ModulePageFilter = NopPageFilter; fn address_filter(&self) -> &Self::AddressFilter {
fn address_filter(&self) -> &Self::ModuleAddressFilter {
&self.filter &self.filter
} }
fn address_filter_mut(&mut self) -> &mut Self::ModuleAddressFilter { fn address_filter_mut(&mut self) -> &mut Self::AddressFilter {
&mut self.filter &mut self.filter
} }
}
#[cfg(feature = "systemmode")] #[cfg(feature = "systemmode")]
fn page_filter(&self) -> &Self::ModulePageFilter { impl<T> HasPageFilter for CallTracerModule<T>
where
T: CallTraceCollectorTuple,
{
type PageFilter = NopPageFilter;
fn page_filter(&self) -> &Self::PageFilter {
&NopPageFilter &NopPageFilter
} }
#[cfg(feature = "systemmode")] fn page_filter_mut(&mut self) -> &mut Self::PageFilter {
fn page_filter_mut(&mut self) -> &mut Self::ModulePageFilter {
unsafe { (&raw mut NOP_PAGE_FILTER).as_mut().unwrap().get_mut() } unsafe { (&raw mut NOP_PAGE_FILTER).as_mut().unwrap().get_mut() }
} }
} }

View File

@ -15,7 +15,7 @@ use serde::{Deserialize, Serialize};
#[cfg(feature = "usermode")] #[cfg(feature = "usermode")]
use crate::capstone; use crate::capstone;
#[cfg(feature = "systemmode")] #[cfg(feature = "systemmode")]
use crate::modules::utils::filters::{NOP_PAGE_FILTER, NopPageFilter}; use crate::modules::utils::filters::{HasPageFilter, NOP_PAGE_FILTER, NopPageFilter};
use crate::{ use crate::{
Qemu, Qemu,
emu::EmulatorModules, emu::EmulatorModules,
@ -95,25 +95,26 @@ where
} }
impl HasAddressFilter for CmpLogModule { impl HasAddressFilter for CmpLogModule {
type ModuleAddressFilter = StdAddressFilter; type AddressFilter = StdAddressFilter;
#[cfg(feature = "systemmode")]
type ModulePageFilter = NopPageFilter;
fn address_filter(&self) -> &Self::ModuleAddressFilter { fn address_filter(&self) -> &Self::AddressFilter {
&self.address_filter &self.address_filter
} }
fn address_filter_mut(&mut self) -> &mut Self::ModuleAddressFilter { fn address_filter_mut(&mut self) -> &mut Self::AddressFilter {
&mut self.address_filter &mut self.address_filter
} }
}
#[cfg(feature = "systemmode")] #[cfg(feature = "systemmode")]
fn page_filter(&self) -> &Self::ModulePageFilter { impl HasPageFilter for CmpLogModule {
type PageFilter = NopPageFilter;
fn page_filter(&self) -> &Self::PageFilter {
&NopPageFilter &NopPageFilter
} }
#[cfg(feature = "systemmode")] fn page_filter_mut(&mut self) -> &mut Self::PageFilter {
fn page_filter_mut(&mut self) -> &mut Self::ModulePageFilter {
unsafe { (&raw mut NOP_PAGE_FILTER).as_mut().unwrap().get_mut() } unsafe { (&raw mut NOP_PAGE_FILTER).as_mut().unwrap().get_mut() }
} }
} }
@ -167,25 +168,26 @@ where
} }
impl HasAddressFilter for CmpLogChildModule { impl HasAddressFilter for CmpLogChildModule {
type ModuleAddressFilter = StdAddressFilter; type AddressFilter = StdAddressFilter;
#[cfg(feature = "systemmode")]
type ModulePageFilter = NopPageFilter;
fn address_filter(&self) -> &Self::ModuleAddressFilter { fn address_filter(&self) -> &Self::AddressFilter {
&self.address_filter &self.address_filter
} }
fn address_filter_mut(&mut self) -> &mut Self::ModuleAddressFilter { fn address_filter_mut(&mut self) -> &mut Self::AddressFilter {
&mut self.address_filter &mut self.address_filter
} }
}
#[cfg(feature = "systemmode")] #[cfg(feature = "systemmode")]
fn page_filter(&self) -> &Self::ModulePageFilter { impl HasPageFilter for CmpLogChildModule {
type PageFilter = NopPageFilter;
fn page_filter(&self) -> &Self::PageFilter {
&NopPageFilter &NopPageFilter
} }
#[cfg(feature = "systemmode")] fn page_filter_mut(&mut self) -> &mut Self::PageFilter {
fn page_filter_mut(&mut self) -> &mut Self::ModulePageFilter {
unsafe { (&raw mut NOP_PAGE_FILTER).as_mut().unwrap().get_mut() } unsafe { (&raw mut NOP_PAGE_FILTER).as_mut().unwrap().get_mut() }
} }
} }
@ -345,16 +347,18 @@ impl CmpLogRoutinesModule {
#[allow(unused_mut)] // cfg dependent #[allow(unused_mut)] // cfg dependent
let mut code = { let mut code = {
#[cfg(feature = "usermode")] #[cfg(feature = "usermode")]
unsafe { {
std::slice::from_raw_parts(qemu.g2h(pc), 512); unsafe { std::slice::from_raw_parts(qemu.g2h(pc), 512) }
} }
#[cfg(feature = "systemmode")] #[cfg(feature = "systemmode")]
&mut [0; 512] {
&mut [0; 512]
}
}; };
#[cfg(feature = "systemmode")] #[cfg(feature = "systemmode")]
unsafe { {
qemu.read_mem(pc, code) unsafe { qemu.read_mem(pc, code) }; // TODO handle faults
}; // TODO handle faults }
let mut iaddr = pc; let mut iaddr = pc;
@ -389,11 +393,15 @@ impl CmpLogRoutinesModule {
iaddr += insn.bytes().len() as GuestAddr; iaddr += insn.bytes().len() as GuestAddr;
#[cfg(feature = "usermode")] #[cfg(feature = "usermode")]
code = unsafe { std::slice::from_raw_parts(qemu.g2h(iaddr), 512) }; {
code = unsafe { std::slice::from_raw_parts(qemu.g2h(iaddr), 512) };
}
#[cfg(feature = "systemmode")] #[cfg(feature = "systemmode")]
unsafe { {
qemu.read_mem(pc, code); unsafe {
} // TODO handle faults qemu.read_mem(pc, code);
} // TODO handle faults
}
} }
} }
@ -425,15 +433,15 @@ where
#[cfg(feature = "usermode")] #[cfg(feature = "usermode")]
impl HasAddressFilter for CmpLogRoutinesModule { impl HasAddressFilter for CmpLogRoutinesModule {
type ModuleAddressFilter = StdAddressFilter; type AddressFilter = StdAddressFilter;
#[cfg(feature = "systemmode")] #[cfg(feature = "systemmode")]
type ModulePageFilter = NopPageFilter; type ModulePageFilter = NopPageFilter;
fn address_filter(&self) -> &Self::ModuleAddressFilter { fn address_filter(&self) -> &Self::AddressFilter {
&self.address_filter &self.address_filter
} }
fn address_filter_mut(&mut self) -> &mut Self::ModuleAddressFilter { fn address_filter_mut(&mut self) -> &mut Self::AddressFilter {
&mut self.address_filter &mut self.address_filter
} }

View File

@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize};
use super::utils::filters::HasAddressFilter; use super::utils::filters::HasAddressFilter;
#[cfg(feature = "systemmode")] #[cfg(feature = "systemmode")]
use crate::modules::utils::filters::{NOP_PAGE_FILTER, NopPageFilter}; use crate::modules::utils::filters::{HasPageFilter, NOP_PAGE_FILTER, NopPageFilter};
use crate::{ use crate::{
Qemu, Qemu,
emu::EmulatorModules, emu::EmulatorModules,
@ -522,25 +522,26 @@ impl<F> HasAddressFilter for DrCovModule<F>
where where
F: AddressFilter, F: AddressFilter,
{ {
type ModuleAddressFilter = F; type AddressFilter = F;
#[cfg(feature = "systemmode")]
type ModulePageFilter = NopPageFilter;
fn address_filter(&self) -> &Self::ModuleAddressFilter { fn address_filter(&self) -> &Self::AddressFilter {
&self.filter &self.filter
} }
fn address_filter_mut(&mut self) -> &mut Self::ModuleAddressFilter { fn address_filter_mut(&mut self) -> &mut Self::AddressFilter {
&mut self.filter &mut self.filter
} }
}
#[cfg(feature = "systemmode")] #[cfg(feature = "systemmode")]
fn page_filter(&self) -> &Self::ModulePageFilter { impl<F> HasPageFilter for DrCovModule<F> {
type PageFilter = NopPageFilter;
fn page_filter(&self) -> &Self::PageFilter {
&NopPageFilter &NopPageFilter
} }
#[cfg(feature = "systemmode")] fn page_filter_mut(&mut self) -> &mut Self::PageFilter {
fn page_filter_mut(&mut self) -> &mut Self::ModulePageFilter {
unsafe { (&raw mut NOP_PAGE_FILTER).as_mut().unwrap().get_mut() } unsafe { (&raw mut NOP_PAGE_FILTER).as_mut().unwrap().get_mut() }
} }
} }

View File

@ -35,6 +35,8 @@ pub use child::{
use libafl::observers::ConstLenMapObserver; use libafl::observers::ConstLenMapObserver;
use super::utils::filters::HasAddressFilter; use super::utils::filters::HasAddressFilter;
#[cfg(feature = "systemmode")]
use super::utils::filters::HasPageFilter;
/// Standard edge coverage module, adapted to most use cases /// Standard edge coverage module, adapted to most use cases
pub type StdEdgeCoverageModule = StdEdgeCoverageFullModule; pub type StdEdgeCoverageModule = StdEdgeCoverageFullModule;
@ -366,27 +368,31 @@ impl<AF, PF, V, const IS_CONST_MAP: bool, const MAP_SIZE: usize> HasAddressFilte
for EdgeCoverageModule<AF, PF, V, IS_CONST_MAP, MAP_SIZE> for EdgeCoverageModule<AF, PF, V, IS_CONST_MAP, MAP_SIZE>
where where
AF: AddressFilter, AF: AddressFilter,
PF: PageFilter,
{ {
type ModuleAddressFilter = AF; type AddressFilter = AF;
#[cfg(feature = "systemmode")] fn address_filter(&self) -> &Self::AddressFilter {
type ModulePageFilter = PF;
fn address_filter(&self) -> &Self::ModuleAddressFilter {
&self.address_filter &self.address_filter
} }
fn address_filter_mut(&mut self) -> &mut Self::ModuleAddressFilter { fn address_filter_mut(&mut self) -> &mut Self::AddressFilter {
&mut self.address_filter &mut self.address_filter
} }
}
#[cfg(feature = "systemmode")] #[cfg(feature = "systemmode")]
fn page_filter(&self) -> &Self::ModulePageFilter { impl<AF, PF, V, const IS_CONST_MAP: bool, const MAP_SIZE: usize> HasPageFilter
for EdgeCoverageModule<AF, PF, V, IS_CONST_MAP, MAP_SIZE>
where
PF: PageFilter,
{
type PageFilter = PF;
fn page_filter(&self) -> &Self::PageFilter {
&self.page_filter &self.page_filter
} }
#[cfg(feature = "systemmode")] fn page_filter_mut(&mut self) -> &mut Self::PageFilter {
fn page_filter_mut(&mut self) -> &mut Self::ModulePageFilter {
&mut self.page_filter &mut self.page_filter
} }
} }

View File

@ -1118,12 +1118,12 @@ where
} }
impl HasAddressFilter for AsanModule { impl HasAddressFilter for AsanModule {
type ModuleAddressFilter = StdAddressFilter; type AddressFilter = StdAddressFilter;
fn address_filter(&self) -> &Self::ModuleAddressFilter { fn address_filter(&self) -> &Self::AddressFilter {
&self.filter &self.filter
} }
fn address_filter_mut(&mut self) -> &mut Self::ModuleAddressFilter { fn address_filter_mut(&mut self) -> &mut Self::AddressFilter {
&mut self.filter &mut self.filter
} }
} }

View File

@ -342,13 +342,13 @@ impl<F> HasAddressFilter for AsanGuestModule<F>
where where
F: AddressFilter, F: AddressFilter,
{ {
type ModuleAddressFilter = F; type AddressFilter = F;
fn address_filter(&self) -> &Self::ModuleAddressFilter { fn address_filter(&self) -> &Self::AddressFilter {
&self.filter &self.filter
} }
fn address_filter_mut(&mut self) -> &mut Self::ModuleAddressFilter { fn address_filter_mut(&mut self) -> &mut Self::AddressFilter {
&mut self.filter &mut self.filter
} }
} }

View File

@ -346,13 +346,13 @@ where
} }
impl HasAddressFilter for InjectionModule { impl HasAddressFilter for InjectionModule {
type ModuleAddressFilter = NopAddressFilter; type AddressFilter = NopAddressFilter;
fn address_filter(&self) -> &Self::ModuleAddressFilter { fn address_filter(&self) -> &Self::AddressFilter {
&NopAddressFilter &NopAddressFilter
} }
fn address_filter_mut(&mut self) -> &mut Self::ModuleAddressFilter { fn address_filter_mut(&mut self) -> &mut Self::AddressFilter {
unsafe { (&raw mut NOP_ADDRESS_FILTER).as_mut().unwrap().get_mut() } unsafe { (&raw mut NOP_ADDRESS_FILTER).as_mut().unwrap().get_mut() }
} }
} }

View File

@ -775,12 +775,12 @@ where
} }
impl HasAddressFilter for SnapshotModule { impl HasAddressFilter for SnapshotModule {
type ModuleAddressFilter = NopAddressFilter; type AddressFilter = NopAddressFilter;
fn address_filter(&self) -> &Self::ModuleAddressFilter { fn address_filter(&self) -> &Self::AddressFilter {
&NopAddressFilter &NopAddressFilter
} }
fn address_filter_mut(&mut self) -> &mut Self::ModuleAddressFilter { fn address_filter_mut(&mut self) -> &mut Self::AddressFilter {
unsafe { (&raw mut NOP_ADDRESS_FILTER).as_mut().unwrap().get_mut() } unsafe { (&raw mut NOP_ADDRESS_FILTER).as_mut().unwrap().get_mut() }
} }
} }

View File

@ -31,7 +31,7 @@ impl<T> AddressFilter for FilterList<T>
where where
T: AddressFilter, T: AddressFilter,
{ {
fn register(&mut self, address_range: Range<GuestAddr>) { fn register(&mut self, address_range: &Range<GuestAddr>) {
match self { match self {
FilterList::AllowList(allow_list) => allow_list.register(address_range), FilterList::AllowList(allow_list) => allow_list.register(address_range),
FilterList::DenyList(deny_list) => deny_list.register(address_range), FilterList::DenyList(deny_list) => deny_list.register(address_range),
@ -69,62 +69,133 @@ where
} }
} }
#[cfg(feature = "usermode")]
pub trait HasStdFilters: HasAddressFilter {}
#[cfg(feature = "systemmode")]
pub trait HasStdFilters: HasAddressFilter + HasPageFilter {}
#[cfg(feature = "usermode")]
pub trait HasStdFiltersTuple: HasAddressFilterTuple {}
#[cfg(feature = "systemmode")]
pub trait HasStdFiltersTuple: HasAddressFilterTuple + HasPageFilterTuple {}
/// Offers accessors to modules' address filters. /// Offers accessors to modules' address filters.
pub trait HasAddressFilter { pub trait HasAddressFilter {
type ModuleAddressFilter: AddressFilter; type AddressFilter: AddressFilter;
#[cfg(feature = "systemmode")]
type ModulePageFilter: PageFilter;
fn address_filter(&self) -> &Self::ModuleAddressFilter;
fn address_filter_mut(&mut self) -> &mut Self::ModuleAddressFilter; fn address_filter(&self) -> &Self::AddressFilter;
fn address_filter_mut(&mut self) -> &mut Self::AddressFilter;
fn update_address_filter(&mut self, qemu: Qemu, filter: Self::ModuleAddressFilter) { fn update_address_filter(&mut self, qemu: Qemu, filter: Self::AddressFilter) {
*self.address_filter_mut() = filter; *self.address_filter_mut() = filter;
// Necessary because some hooks filter during TB generation. // Necessary because some hooks filter during TB generation.
qemu.flush_jit(); qemu.flush_jit();
} }
fn allow_address_range(&mut self, address_range: &Range<GuestAddr>) {
self.address_filter_mut().register(address_range);
}
#[cfg(feature = "systemmode")] fn allowed_address(&self, address: &GuestAddr) -> bool {
fn page_filter(&self) -> &Self::ModulePageFilter; self.address_filter().allowed(address)
#[cfg(feature = "systemmode")] }
fn page_filter_mut(&mut self) -> &mut Self::ModulePageFilter; }
#[cfg(feature = "systemmode")]
fn update_page_filter(&mut self, qemu: Qemu, filter: Self::ModulePageFilter) { pub trait HasAddressFilterTuple {
fn allow_address_range_all(&mut self, address_range: &Range<GuestAddr>);
fn allowed_address_all(&self, address: &GuestAddr) -> bool;
}
impl HasAddressFilterTuple for () {
fn allow_address_range_all(&mut self, _address_range: &Range<GuestAddr>) {}
fn allowed_address_all(&self, _address: &GuestAddr) -> bool {
true
}
}
impl<Head, Tail> HasAddressFilterTuple for (Head, Tail)
where
Head: HasAddressFilter,
Tail: HasAddressFilterTuple,
{
fn allow_address_range_all(&mut self, address_range: &Range<GuestAddr>) {
self.0.allow_address_range(address_range);
self.1.allow_address_range_all(address_range);
}
fn allowed_address_all(&self, address: &GuestAddr) -> bool {
self.0.allowed_address(address) && self.1.allowed_address_all(address)
}
}
#[cfg(feature = "usermode")]
impl<M> HasStdFilters for M where M: HasAddressFilter {}
#[cfg(feature = "systemmode")]
impl<M> HasStdFilters for M where M: HasAddressFilter + HasPageFilter {}
impl HasStdFiltersTuple for () {}
impl<Head, Tail> HasStdFiltersTuple for (Head, Tail)
where
Head: HasStdFilters,
Tail: HasStdFiltersTuple,
{
}
/// Offers accessors to modules' page filters.
#[cfg(feature = "systemmode")]
pub trait HasPageFilter {
type PageFilter: PageFilter;
fn page_filter(&self) -> &Self::PageFilter;
fn page_filter_mut(&mut self) -> &mut Self::PageFilter;
fn update_page_filter(&mut self, qemu: Qemu, filter: Self::PageFilter) {
*self.page_filter_mut() = filter; *self.page_filter_mut() = filter;
// Necessary because some hooks filter during TB generation. // Necessary because some hooks filter during TB generation.
qemu.flush_jit(); qemu.flush_jit();
} }
} fn allow_page_id(&mut self, page_id: GuestPhysAddr) {
self.page_filter_mut().register(page_id);
pub trait HasAddressFilterTuples {
fn allow_address_range_all(&mut self, address_range: Range<GuestAddr>);
#[cfg(feature = "systemmode")]
fn allow_page_id_all(&mut self, page_id: GuestPhysAddr);
}
impl HasAddressFilterTuples for () {
fn allow_address_range_all(&mut self, _address_range: Range<GuestAddr>) {}
#[cfg(feature = "systemmode")]
fn allow_page_id_all(&mut self, _page_id: GuestPhysAddr) {}
}
impl<Head, Tail> HasAddressFilterTuples for (Head, Tail)
where
Head: HasAddressFilter,
Tail: HasAddressFilterTuples,
{
fn allow_address_range_all(&mut self, address_range: Range<GuestAddr>) {
self.0.address_filter_mut().register(address_range.clone());
self.1.allow_address_range_all(address_range);
} }
#[cfg(feature = "systemmode")] fn allowed_page_id(&self, page_id: &GuestPhysAddr) -> bool {
self.page_filter().allowed(page_id)
}
}
#[cfg(feature = "systemmode")]
pub trait HasPageFilterTuple {
fn allow_page_id_all(&mut self, page_id: GuestPhysAddr);
fn allowed_page_id_all(&self, page_id: &GuestPhysAddr) -> bool;
}
#[cfg(feature = "systemmode")]
impl HasPageFilterTuple for () {
fn allow_page_id_all(&mut self, _page_id: GuestPhysAddr) {}
fn allowed_page_id_all(&self, _page_id: &GuestPhysAddr) -> bool {
true
}
}
#[cfg(feature = "systemmode")]
impl<Head, Tail> HasPageFilterTuple for (Head, Tail)
where
Head: HasPageFilter,
Tail: HasPageFilterTuple,
{
fn allow_page_id_all(&mut self, page_id: GuestPhysAddr) { fn allow_page_id_all(&mut self, page_id: GuestPhysAddr) {
self.0.page_filter_mut().register(page_id); self.0.allow_page_id(page_id);
self.1.allow_page_id_all(page_id); self.1.allow_page_id_all(page_id);
} }
fn allowed_page_id_all(&self, page_id: &GuestPhysAddr) -> bool {
self.0.allowed_page_id(page_id) && self.1.allowed_page_id_all(page_id)
}
} }
/// An address filter list. /// An address filter list.
@ -172,8 +243,8 @@ impl AddressFilterVec {
} }
impl AddressFilter for AddressFilterVec { impl AddressFilter for AddressFilterVec {
fn register(&mut self, address_range: Range<GuestAddr>) { fn register(&mut self, address_range: &Range<GuestAddr>) {
self.registered_addresses.push(address_range); self.registered_addresses.push(address_range.clone());
if let Some(qemu) = Qemu::get() { if let Some(qemu) = Qemu::get() {
qemu.flush_jit(); qemu.flush_jit();
@ -196,7 +267,7 @@ impl AddressFilter for AddressFilterVec {
} }
impl AddressFilter for StdAddressFilter { impl AddressFilter for StdAddressFilter {
fn register(&mut self, address_range: Range<GuestAddr>) { fn register(&mut self, address_range: &Range<GuestAddr>) {
self.0.register(address_range); self.0.register(address_range);
} }
@ -279,7 +350,7 @@ impl PageFilter for StdPageFilter {
} }
pub trait AddressFilter: 'static + Debug { pub trait AddressFilter: 'static + Debug {
fn register(&mut self, address_range: Range<GuestAddr>); fn register(&mut self, address_range: &Range<GuestAddr>);
fn allowed(&self, address: &GuestAddr) -> bool; fn allowed(&self, address: &GuestAddr) -> bool;
} }
@ -287,7 +358,7 @@ pub trait AddressFilter: 'static + Debug {
#[derive(Debug)] #[derive(Debug)]
pub struct NopAddressFilter; pub struct NopAddressFilter;
impl AddressFilter for NopAddressFilter { impl AddressFilter for NopAddressFilter {
fn register(&mut self, _address: Range<GuestAddr>) {} fn register(&mut self, _address: &Range<GuestAddr>) {}
fn allowed(&self, _address: &GuestAddr) -> bool { fn allowed(&self, _address: &GuestAddr) -> bool {
true true
@ -319,15 +390,12 @@ pub(crate) static mut NOP_PAGE_FILTER: UnsafeCell<NopPageFilter> = UnsafeCell::n
#[cfg(all(feature = "systemmode", test))] #[cfg(all(feature = "systemmode", test))]
mod tests { mod tests {
use libafl::{HasMetadata, inputs::NopInput, state::NopState};
use libafl_bolts::tuples::tuple_list; use libafl_bolts::tuples::tuple_list;
use crate::modules::{ use crate::modules::utils::filters::{
EmulatorModule, AddressFilter, HasAddressFilter, HasAddressFilterTuple, HasPageFilter, HasPageFilterTuple,
utils::filters::{ HasStdFilters, NopAddressFilter, NopPageFilter, PageFilter, StdAddressFilter,
AddressFilter, NopAddressFilter, NopPageFilter, PageFilter, StdAddressFilter, StdPageFilter,
StdPageFilter,
},
}; };
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -336,42 +404,47 @@ mod tests {
page_filter: PF, page_filter: PF,
} }
impl<I, S, AF, PF> EmulatorModule<I, S> for DummyModule<AF, PF> impl<AF, PF> HasAddressFilter for DummyModule<AF, PF>
where where
AF: AddressFilter + 'static, AF: AddressFilter,
PF: PageFilter + 'static,
I: Unpin,
S: Unpin + HasMetadata,
{ {
type ModuleAddressFilter = AF; type AddressFilter = AF;
type ModulePageFilter = PF;
fn address_filter(&self) -> &Self::ModuleAddressFilter { fn address_filter(&self) -> &Self::AddressFilter {
&self.address_filter &self.address_filter
} }
fn address_filter_mut(&mut self) -> &mut Self::ModuleAddressFilter { fn address_filter_mut(&mut self) -> &mut Self::AddressFilter {
&mut self.address_filter &mut self.address_filter
} }
}
fn page_filter(&self) -> &Self::ModulePageFilter { impl<AF, PF> HasPageFilter for DummyModule<AF, PF>
where
PF: PageFilter,
{
type PageFilter = PF;
fn page_filter(&self) -> &Self::PageFilter {
&self.page_filter &self.page_filter
} }
fn page_filter_mut(&mut self) -> &mut Self::ModulePageFilter { fn page_filter_mut(&mut self) -> &mut Self::PageFilter {
&mut self.page_filter &mut self.page_filter
} }
} }
fn gen_module<AF, PF, I, S>( impl<AF, PF> HasStdFilters for DummyModule<AF, PF>
af: AF, where
pf: PF, AF: AddressFilter,
) -> impl EmulatorModule<I, S, ModuleAddressFilter = AF, ModulePageFilter = PF> PF: PageFilter,
{
}
fn gen_module<AF, PF>(af: AF, pf: PF) -> impl HasStdFilters<AddressFilter = AF, PageFilter = PF>
where where
AF: AddressFilter, AF: AddressFilter,
PF: PageFilter, PF: PageFilter,
I: Unpin,
S: HasMetadata + Unpin,
{ {
DummyModule { DummyModule {
address_filter: af, address_filter: af,
@ -399,82 +472,79 @@ mod tests {
#[test] #[test]
fn test_filter_nop() { fn test_filter_nop() {
let module = gen_module::<NopAddressFilter, NopPageFilter, NopState<NopInput>>( let mut module =
NopAddressFilter, gen_module::<NopAddressFilter, NopPageFilter>(NopAddressFilter, NopPageFilter);
NopPageFilter,
);
let mut modules = tuple_list!(module);
modules.allow_address_range_all(0x100..0x200); module.allow_address_range(&(0x100..0x200));
modules.allow_address_range_all(0x300..0x400); module.allow_address_range(&(0x300..0x400));
modules.allow_page_id_all(0xaaaa); module.allow_page_id(0xaaaa);
modules.allow_page_id_all(0xbbbb); module.allow_page_id(0xbbbb);
assert!(modules.0.address_filter().allowed(&0xff)); assert!(module.allowed_address(&0xff));
assert!(modules.0.address_filter().allowed(&0x200)); assert!(module.allowed_address(&0x200));
assert!(modules.0.address_filter().allowed(&0x201)); assert!(module.allowed_address(&0x201));
assert!(modules.0.address_filter().allowed(&0x300)); assert!(module.allowed_address(&0x300));
assert!(modules.0.page_filter().allowed(&0xaaaa)); assert!(module.allowed_page_id(&0xaaaa));
assert!(modules.0.page_filter().allowed(&0xbbbb)); assert!(module.allowed_page_id(&0xbbbb));
assert!(modules.0.page_filter().allowed(&0xcccc)); assert!(module.allowed_page_id(&0xcccc));
} }
#[test] #[test]
fn test_filters_simple() { fn test_filters_simple() {
let module = gen_module::<StdAddressFilter, StdPageFilter, NopState<NopInput>>( let module = gen_module::<StdAddressFilter, StdPageFilter>(
StdAddressFilter::default(), StdAddressFilter::default(),
StdPageFilter::default(), StdPageFilter::default(),
); );
let mut modules = tuple_list!(module); let mut modules = tuple_list!(module);
assert!(modules.0.address_filter().allowed(&0x000)); assert!(modules.allowed_address_all(&0x000));
assert!(modules.0.address_filter().allowed(&0x100)); assert!(modules.allowed_address_all(&0x100));
assert!(modules.0.address_filter().allowed(&0x200)); assert!(modules.allowed_address_all(&0x200));
assert!(modules.0.address_filter().allowed(&0xffffffff)); assert!(modules.allowed_address_all(&0xffffffff));
assert!(modules.0.page_filter().allowed(&0xabcd)); assert!(modules.allowed_page_id_all(&0xabcd));
modules.allow_address_range_all(0x100..0x200); modules.allow_address_range_all(&(0x100..0x200));
modules.allow_address_range_all(0x300..0x400); modules.allow_address_range_all(&(0x300..0x400));
modules.allow_page_id_all(0xaaaa); modules.allow_page_id_all(0xaaaa);
modules.allow_page_id_all(0xbbbb); modules.allow_page_id_all(0xbbbb);
assert!(modules.0.address_filter().allowed(&0x100)); assert!(modules.allowed_address_all(&0x100));
assert!(modules.0.address_filter().allowed(&0x101)); assert!(modules.allowed_address_all(&0x101));
assert!(modules.0.address_filter().allowed(&0x1ff)); assert!(modules.allowed_address_all(&0x1ff));
assert!(modules.0.address_filter().allowed(&0x301)); assert!(modules.allowed_address_all(&0x301));
assert!(!modules.0.address_filter().allowed(&0xff)); assert!(!modules.allowed_address_all(&0xff));
assert!(!modules.0.address_filter().allowed(&0x200)); assert!(!modules.allowed_address_all(&0x200));
assert!(!modules.0.address_filter().allowed(&0x201)); assert!(!modules.allowed_address_all(&0x201));
assert!(modules.0.page_filter().allowed(&0xaaaa)); assert!(modules.allowed_page_id_all(&0xaaaa));
assert!(modules.0.page_filter().allowed(&0xbbbb)); assert!(modules.allowed_page_id_all(&0xbbbb));
assert!(!modules.0.page_filter().allowed(&0xcccc)); assert!(!modules.allowed_page_id_all(&0xcccc));
} }
#[test] #[test]
fn test_filters_multiple() { fn test_filters_multiple() {
let module1 = gen_module::<StdAddressFilter, StdPageFilter, NopState<NopInput>>( let module1 = gen_module::<StdAddressFilter, StdPageFilter>(
StdAddressFilter::default(), StdAddressFilter::default(),
StdPageFilter::default(), StdPageFilter::default(),
); );
let module2 = gen_module::<StdAddressFilter, StdPageFilter, NopState<NopInput>>( let module2 = gen_module::<StdAddressFilter, StdPageFilter>(
StdAddressFilter::default(), StdAddressFilter::default(),
StdPageFilter::default(), StdPageFilter::default(),
); );
let module3 = gen_module::<StdAddressFilter, StdPageFilter, NopState<NopInput>>( let module3 = gen_module::<StdAddressFilter, StdPageFilter>(
StdAddressFilter::default(), StdAddressFilter::default(),
StdPageFilter::default(), StdPageFilter::default(),
); );
let mut modules = tuple_list!(module1, module2, module3); let mut modules = tuple_list!(module1, module2, module3);
modules.allow_address_range_all(0x100..0x200); modules.allow_address_range_all(&(0x100..0x200));
modules.allow_address_range_all(0x300..0x400); modules.allow_address_range_all(&(0x300..0x400));
modules.allow_page_id_all(0xaaaa); modules.allow_page_id_all(0xaaaa);
modules.allow_page_id_all(0xbbbb); modules.allow_page_id_all(0xbbbb);