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 ----
- name: Run a normal build
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
run: cargo build --examples --verbose

6
.gitignore vendored
View File

@ -79,3 +79,9 @@ fuzzer_libpng*
# Sometimes this happens
rustc-ice-*
# perf files
*.mm_profdata
# backup files
*.bak

View File

@ -41,7 +41,7 @@ use libafl_qemu::{
executor::QemuExecutor,
modules::{
cmplog::CmpLogObserver, edges::StdEdgeCoverageClassicModule,
utils::filters::HasAddressFilterTuples, CmpLogModule, EmulatorModuleTuple,
utils::filters::HasAddressFilterTuple, CmpLogModule, EmulatorModuleTuple,
},
FastSnapshotManager, NopSnapshotManager, QemuInitError,
};
@ -78,12 +78,12 @@ fn get_emulator<C, ET, I, S>(
QemuInitError,
>
where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples,
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuple,
I: HasTargetBytes + Unpin,
S: HasExecutions + Unpin,
{
// 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()
.qemu_parameters(args)

View File

@ -41,7 +41,7 @@ use libafl_qemu::{
executor::QemuExecutor,
modules::{
cmplog::CmpLogObserver, edges::StdEdgeCoverageClassicModule,
utils::filters::HasAddressFilterTuples, CmpLogModule, EmulatorModuleTuple,
utils::filters::HasAddressFilterTuple, CmpLogModule, EmulatorModuleTuple,
},
FastSnapshotManager, NopSnapshotManager, QemuInitError, QemuSnapshotManager,
};
@ -78,12 +78,12 @@ fn get_emulator<C, ET, I, S>(
QemuInitError,
>
where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples,
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuple,
I: HasTargetBytes + Unpin,
S: HasExecutions + Unpin,
{
// 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()
.qemu_parameters(args)

View File

@ -8,10 +8,10 @@ use core::{fmt::Debug, marker::PhantomData, time::Duration};
use libafl_bolts::ClientId;
#[cfg(all(feature = "std", any(windows, not(feature = "fork"))))]
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))]
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")]
use libafl_bolts::{
os::CTRL_C_EXIT,
@ -510,6 +510,13 @@ where
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)]
if !staterestorer.has_content() {
#[cfg(unix)]

View File

@ -355,7 +355,9 @@ pub struct InProcessExecutorHandlerData {
/// the pointer to the executor
pub executor_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
#[cfg(feature = "std")]
@ -376,6 +378,9 @@ unsafe impl Send for InProcessExecutorHandlerData {}
unsafe impl Sync for InProcessExecutorHandlerData {}
impl InProcessExecutorHandlerData {
#[cfg(feature = "std")]
const SIGNAL_HANDLER_MAX_DEPTH: usize = 3;
/// # Safety
/// 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)))]
@ -418,11 +423,19 @@ impl InProcessExecutorHandlerData {
!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)))]
pub(crate) fn set_in_handler(&mut self, v: bool) -> bool {
let old = self.in_handler;
self.in_handler = v;
old
pub(crate) fn signal_handler_enter(&mut self) -> (bool, usize) {
self.signal_handler_depth += 1;
(
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.
@ -500,7 +513,8 @@ pub static mut GLOBAL_STATE: InProcessExecutorHandlerData = InProcessExecutorHan
// The current input for signal handling
current_input_ptr: ptr::null(),
in_handler: false,
#[cfg(feature = "std")]
signal_handler_depth: 0,
// The crash handler fn
#[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> {
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.
/// windows crash/timeout handler and asan death callback
#[cfg(windows)]
#[cfg(all(windows, feature = "std"))]
pub mod windows;
/// *nix crash handler

View File

@ -5,7 +5,10 @@ pub mod unix_signal_handler {
use core::mem::transmute;
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 crate::{
@ -50,11 +53,13 @@ pub mod unix_signal_handler {
) {
unsafe {
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 {
log::error!("We crashed inside a crash handler, but this should never happen!");
libc::exit(56);
if max_depth_reached {
log::error!(
"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 {
@ -67,11 +72,11 @@ pub mod unix_signal_handler {
_ => {
if !(*data).crash_handler.is_null() {
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 {
old_hook(panic_info);
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 {
log::error!("We crashed inside a crash panic hook, but this should never happen!");
libc::exit(56);
if max_depth_reached {
log::error!(
"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() {
@ -121,7 +128,8 @@ pub mod unix_signal_handler {
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`
#[cfg(all(windows, feature = "std"))]
pub mod windows_asan_handler {
use alloc::string::String;
use core::sync::atomic::{Ordering, compiler_fence};
use libafl_bolts::os::SIGNAL_RECURSION_EXIT;
use windows::Win32::System::Threading::{
CRITICAL_SECTION, EnterCriticalSection, ExitProcess, LeaveCriticalSection,
};
@ -35,13 +35,13 @@ pub mod windows_asan_handler {
{
unsafe {
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 asan death handler, but this should never happen!"
);
ExitProcess(56);
ExitProcess(SIGNAL_RECURSION_EXIT as u32);
}
// 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
pub mod windows_exception_handler {
#[cfg(feature = "std")]
@ -126,9 +125,12 @@ pub mod windows_exception_handler {
#[cfg(feature = "std")]
use std::panic;
use libafl_bolts::os::windows_exceptions::{
CRASH_EXCEPTIONS, EXCEPTION_HANDLERS_SIZE, EXCEPTION_POINTERS, ExceptionCode,
ExceptionHandler,
use libafl_bolts::os::{
SIGNAL_RECURSION_EXIT,
windows_exceptions::{
CRASH_EXCEPTIONS, EXCEPTION_HANDLERS_SIZE, EXCEPTION_POINTERS, ExceptionCode,
ExceptionHandler,
},
};
use windows::Win32::System::Threading::{
CRITICAL_SECTION, EnterCriticalSection, ExitProcess, LeaveCriticalSection,
@ -168,18 +170,18 @@ pub mod windows_exception_handler {
) {
unsafe {
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!");
ExitProcess(56);
ExitProcess(SIGNAL_RECURSION_EXIT as u32);
}
if !(*data).crash_handler.is_null() {
let func: HandlerFuncPtr = transmute((*data).crash_handler);
(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();
panic::set_hook(Box::new(move |panic_info| unsafe {
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!");
ExitProcess(56);
ExitProcess(SIGNAL_RECURSION_EXIT as u32);
}
// Have we set a timer_before?
@ -252,7 +254,7 @@ pub mod windows_exception_handler {
ExitProcess(1);
}
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,
}
/// The special exit code when the target signal handler is crashing recursively
pub const SIGNAL_RECURSION_EXIT: i32 = 101;
#[cfg(unix)]
impl ChildHandle {
/// Block until the child exited and the status code becomes available

View File

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

View File

@ -34,7 +34,7 @@ use crate::{
},
},
get_exit_arch_regs,
modules::{EmulatorModuleTuple, utils::filters::HasAddressFilterTuples},
modules::{EmulatorModuleTuple, utils::filters::HasStdFiltersTuple},
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>
where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples,
ET: EmulatorModuleTuple<I, S> + HasStdFiltersTuple,
I: HasTargetBytes + Unpin,
S: Unpin,
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>]
where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples,
ET: EmulatorModuleTuple<I, S> + HasStdFiltersTuple,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
@ -296,7 +296,7 @@ pub struct NextPayloadCommand;
impl<C, ET, I, S, SM> IsCommand<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for NextPayloadCommand
where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples,
ET: EmulatorModuleTuple<I, S> + HasStdFiltersTuple,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
@ -360,7 +360,7 @@ pub struct SubmitCR3Command;
impl<C, ET, I, S, SM> IsCommand<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for SubmitCR3Command
where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples,
ET: EmulatorModuleTuple<I, S> + HasStdFiltersTuple,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
@ -408,7 +408,7 @@ impl RangeSubmitCommand {
impl<C, ET, I, S, SM> IsCommand<C, NyxCommandManager<S>, NyxEmulatorDriver, ET, I, S, SM>
for RangeSubmitCommand
where
ET: EmulatorModuleTuple<I, S> + HasAddressFilterTuples,
ET: EmulatorModuleTuple<I, S> + HasStdFiltersTuple,
I: HasTargetBytes + Unpin,
S: Unpin,
SM: IsSnapshotManager,
@ -440,7 +440,7 @@ where
emu.modules_mut()
.modules_mut()
.allow_address_range_all(self.allowed_range.clone());
.allow_address_range_all(&self.allowed_range);
Ok(None)
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize};
use super::utils::filters::HasAddressFilter;
#[cfg(feature = "systemmode")]
use crate::modules::utils::filters::{NOP_PAGE_FILTER, NopPageFilter};
use crate::modules::utils::filters::{HasPageFilter, NOP_PAGE_FILTER, NopPageFilter};
use crate::{
Qemu,
emu::EmulatorModules,
@ -522,25 +522,26 @@ impl<F> HasAddressFilter for DrCovModule<F>
where
F: AddressFilter,
{
type ModuleAddressFilter = F;
#[cfg(feature = "systemmode")]
type ModulePageFilter = NopPageFilter;
type AddressFilter = F;
fn address_filter(&self) -> &Self::ModuleAddressFilter {
fn address_filter(&self) -> &Self::AddressFilter {
&self.filter
}
fn address_filter_mut(&mut self) -> &mut Self::ModuleAddressFilter {
fn address_filter_mut(&mut self) -> &mut Self::AddressFilter {
&mut self.filter
}
}
#[cfg(feature = "systemmode")]
fn page_filter(&self) -> &Self::ModulePageFilter {
#[cfg(feature = "systemmode")]
impl<F> HasPageFilter for DrCovModule<F> {
type PageFilter = NopPageFilter;
fn page_filter(&self) -> &Self::PageFilter {
&NopPageFilter
}
#[cfg(feature = "systemmode")]
fn page_filter_mut(&mut self) -> &mut Self::ModulePageFilter {
fn page_filter_mut(&mut self) -> &mut Self::PageFilter {
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 super::utils::filters::HasAddressFilter;
#[cfg(feature = "systemmode")]
use super::utils::filters::HasPageFilter;
/// Standard edge coverage module, adapted to most use cases
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>
where
AF: AddressFilter,
PF: PageFilter,
{
type ModuleAddressFilter = AF;
type AddressFilter = AF;
#[cfg(feature = "systemmode")]
type ModulePageFilter = PF;
fn address_filter(&self) -> &Self::ModuleAddressFilter {
fn address_filter(&self) -> &Self::AddressFilter {
&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
}
}
#[cfg(feature = "systemmode")]
fn page_filter(&self) -> &Self::ModulePageFilter {
#[cfg(feature = "systemmode")]
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
}
#[cfg(feature = "systemmode")]
fn page_filter_mut(&mut self) -> &mut Self::ModulePageFilter {
fn page_filter_mut(&mut self) -> &mut Self::PageFilter {
&mut self.page_filter
}
}

View File

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

View File

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

View File

@ -346,13 +346,13 @@ where
}
impl HasAddressFilter for InjectionModule {
type ModuleAddressFilter = NopAddressFilter;
type AddressFilter = NopAddressFilter;
fn address_filter(&self) -> &Self::ModuleAddressFilter {
fn address_filter(&self) -> &Self::AddressFilter {
&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() }
}
}

View File

@ -775,12 +775,12 @@ where
}
impl HasAddressFilter for SnapshotModule {
type ModuleAddressFilter = NopAddressFilter;
fn address_filter(&self) -> &Self::ModuleAddressFilter {
type AddressFilter = NopAddressFilter;
fn address_filter(&self) -> &Self::AddressFilter {
&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() }
}
}

View File

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