From 157f3bc323423dfb74a07cc82046ed012ba8ab2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Bene=C5=A1?= Date: Tue, 17 Dec 2024 23:11:03 +0000 Subject: [PATCH] feat(core): add MemoryAccessOptions for fine-tuning memory access monitoring --- crates/vmi-core/src/core/memory_access.rs | 24 +++++++++++++++++ crates/vmi-core/src/core/mod.rs | 2 +- crates/vmi-core/src/driver.rs | 14 ++++++++-- crates/vmi-core/src/lib.rs | 20 ++++++++++++-- crates/vmi-driver-xen/src/driver.rs | 33 +++++++++++++++++++++-- crates/vmi-driver-xen/src/lib.rs | 16 +++++++++-- 6 files changed, 100 insertions(+), 9 deletions(-) diff --git a/crates/vmi-core/src/core/memory_access.rs b/crates/vmi-core/src/core/memory_access.rs index ac1b949..6632b95 100644 --- a/crates/vmi-core/src/core/memory_access.rs +++ b/crates/vmi-core/src/core/memory_access.rs @@ -27,6 +27,30 @@ bitflags::bitflags! { } } +bitflags::bitflags! { + /// Options for controlling memory access monitoring. + /// + /// These options can be used to fine-tune the behavior of memory access + /// monitoring, allowing you to ignore certain types of memory accesses + /// and improve performance. + #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] + pub struct MemoryAccessOptions: u8 { + /// Ignore page-walk updates caused by the CPU. + /// + /// When this flag is set, memory accesses that are solely the result of + /// CPU-initiated page-table walks will not trigger an [`EventMemoryAccess`]. + /// This is useful for filtering out irrelevant events when monitoring + /// page-table modifications. + /// + /// # Notes + /// + /// This option is only effective when the [`MemoryAccess:W`] is not set. + /// + /// [`EventMemoryAccess`]: ../vmi_arch_amd64/struct.EventMemoryAccess.html + const IGNORE_PAGE_WALK_UPDATES = 0b00000001; + } +} + impl std::fmt::Display for MemoryAccess { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { let mut result = [b'-'; 3]; diff --git a/crates/vmi-core/src/core/mod.rs b/crates/vmi-core/src/core/mod.rs index 041bea4..f653846 100644 --- a/crates/vmi-core/src/core/mod.rs +++ b/crates/vmi-core/src/core/mod.rs @@ -12,7 +12,7 @@ pub use self::{ address_context::AddressContext, hex::Hex, info::VmiInfo, - memory_access::MemoryAccess, + memory_access::{MemoryAccess, MemoryAccessOptions}, vcpu_id::VcpuId, view::View, }; diff --git a/crates/vmi-core/src/driver.rs b/crates/vmi-core/src/driver.rs index 6b9d471..b5b0059 100644 --- a/crates/vmi-core/src/driver.rs +++ b/crates/vmi-core/src/driver.rs @@ -1,8 +1,8 @@ use std::time::Duration; use crate::{ - Architecture, Gfn, MemoryAccess, VcpuId, View, VmiError, VmiEvent, VmiEventResponse, VmiInfo, - VmiMappedPage, + Architecture, Gfn, MemoryAccess, MemoryAccessOptions, VcpuId, View, VmiError, VmiEvent, + VmiEventResponse, VmiInfo, VmiMappedPage, }; /// A trait for implementing a VMI driver. @@ -39,6 +39,16 @@ pub trait VmiDriver { fn set_memory_access(&self, gfn: Gfn, view: View, access: MemoryAccess) -> Result<(), VmiError>; + /// Sets the memory access permissions for a specific GFN with additional + /// options. + fn set_memory_access_with_options( + &self, + gfn: Gfn, + view: View, + access: MemoryAccess, + options: MemoryAccessOptions, + ) -> Result<(), VmiError>; + /// Reads a page of memory from the virtual machine. fn read_page(&self, gfn: Gfn) -> Result; diff --git a/crates/vmi-core/src/lib.rs b/crates/vmi-core/src/lib.rs index 43098b3..0383a3a 100644 --- a/crates/vmi-core/src/lib.rs +++ b/crates/vmi-core/src/lib.rs @@ -20,8 +20,8 @@ pub use self::{ arch::{Architecture, Registers}, context::{VmiContext, VmiContextProber, VmiOsContext, VmiOsContextProber}, core::{ - AccessContext, AddressContext, Gfn, Hex, MemoryAccess, Pa, TranslationMechanism, Va, - VcpuId, View, VmiInfo, + AccessContext, AddressContext, Gfn, Hex, MemoryAccess, MemoryAccessOptions, Pa, + TranslationMechanism, Va, VcpuId, View, VmiInfo, }, driver::VmiDriver, error::{PageFault, PageFaults, VmiError}, @@ -371,6 +371,22 @@ where self.driver.set_memory_access(gfn, view, access) } + /// Sets the memory access permissions for a specific guest frame number + /// (GFN) with additional options. + /// + /// In addition to the basic read, write, and execute permissions, this + /// method allows you to specify additional options for the memory access. + pub fn set_memory_access_with_options( + &self, + gfn: Gfn, + view: View, + access: MemoryAccess, + options: MemoryAccessOptions, + ) -> Result<(), VmiError> { + self.driver + .set_memory_access_with_options(gfn, view, access, options) + } + /// Allocates the next available guest frame number (GFN). /// /// This method finds and allocates the next free GFN after the current diff --git a/crates/vmi-driver-xen/src/driver.rs b/crates/vmi-driver-xen/src/driver.rs index 836c8a7..0f00b66 100644 --- a/crates/vmi-driver-xen/src/driver.rs +++ b/crates/vmi-driver-xen/src/driver.rs @@ -6,8 +6,8 @@ use std::{ }; use vmi_core::{ - Architecture, Gfn, MemoryAccess, VcpuId, View, VmiEvent, VmiEventResponse, VmiInfo, - VmiMappedPage, + Architecture, Gfn, MemoryAccess, MemoryAccessOptions, VcpuId, View, VmiEvent, VmiEventResponse, + VmiInfo, VmiMappedPage, }; use xen::{ ctrl::VmEventRing, XenAltP2M, XenAltP2MView, XenControl, XenDeviceModel, XenDomain, @@ -136,6 +136,35 @@ where } } + pub fn set_memory_access_with_options( + &self, + gfn: Gfn, + view: View, + access: MemoryAccess, + options: MemoryAccessOptions, + ) -> Result<(), Error> { + tracing::trace!(%gfn, %view, %access, "set memory access"); + + let mut xen_access = access.into_ext(); + + if options.contains(MemoryAccessOptions::IGNORE_PAGE_WALK_UPDATES) { + if access != MemoryAccess::R { + return Err(Error::NotSupported); + } + + xen_access = xen::MemoryAccess::R2PW; + } + + if view.0 == 0 { + return Ok(self.domain.set_mem_access(gfn.into(), xen_access)?); + } + + match self.views.borrow().get(&view.0) { + Some(view) => Ok(view.set_mem_access(gfn.into(), xen_access)?), + None => Err(Error::ViewNotFound), + } + } + pub fn read_page(&self, gfn: Gfn) -> Result { let page = self.foreign_memory.map( self.domain.id(), diff --git a/crates/vmi-driver-xen/src/lib.rs b/crates/vmi-driver-xen/src/lib.rs index 2bb4805..508ebf9 100644 --- a/crates/vmi-driver-xen/src/lib.rs +++ b/crates/vmi-driver-xen/src/lib.rs @@ -9,8 +9,8 @@ mod error; use std::time::Duration; use vmi_core::{ - Architecture, Gfn, MemoryAccess, VcpuId, View, VmiDriver, VmiError, VmiEvent, VmiEventResponse, - VmiInfo, VmiMappedPage, + Architecture, Gfn, MemoryAccess, MemoryAccessOptions, VcpuId, View, VmiDriver, VmiError, + VmiEvent, VmiEventResponse, VmiInfo, VmiMappedPage, }; use xen::XenDomainId; @@ -80,6 +80,18 @@ where Ok(self.inner.set_memory_access(gfn, view, access)?) } + fn set_memory_access_with_options( + &self, + gfn: Gfn, + view: View, + access: MemoryAccess, + options: MemoryAccessOptions, + ) -> Result<(), VmiError> { + Ok(self + .inner + .set_memory_access_with_options(gfn, view, access, options)?) + } + fn read_page(&self, gfn: Gfn) -> Result { Ok(self.inner.read_page(gfn)?) }