Skip to main content

vmi_core/os/
process.rs

1use super::{RegionPredicate, VmiOs, VmiOsImageArchitecture, impl_ops, impl_predicate};
2use crate::{Pa, Va, VmiDriver, VmiError, VmiVa};
3
4impl_ops! {
5    /// A process ID within a system.
6    pub struct ProcessId(pub u32);
7}
8
9impl_ops! {
10    /// A process object within a system.
11    ///
12    /// Equivalent to `EPROCESS*` on Windows or `task_struct*` on Linux.
13    pub struct ProcessObject(pub Va);
14}
15
16impl VmiVa for ProcessObject {
17    fn va(&self) -> Va {
18        self.0
19    }
20}
21
22impl ProcessObject {
23    /// Checks if the process object is a null reference.
24    pub fn is_null(&self) -> bool {
25        self.0.0 == 0
26    }
27
28    /// Converts the process object to a 64-bit unsigned integer.
29    pub fn to_u64(&self) -> u64 {
30        self.0.0
31    }
32}
33
34impl_predicate! {
35    /// Predicate used by [`VmiOsExt::find_process`].
36    ///
37    /// [`VmiOsExt::find_process`]: super::VmiOsExt::find_process
38    pub trait ProcessPredicate & impl for &str {
39        fn matches(&self, process: &Os::Process<'_>) -> Result<bool, VmiError> {
40            Ok(process.name()?.eq_ignore_ascii_case(self))
41        }
42    }
43
44    #[any]
45    pub struct AnyProcess;
46}
47
48impl<Os> ProcessPredicate<Os> for ProcessId
49where
50    Os: VmiOs,
51{
52    fn matches(&self, process: &Os::Process<'_>) -> Result<bool, VmiError> {
53        Ok(process.id()? == *self)
54    }
55}
56
57/// A trait for process objects.
58///
59/// This trait provides an abstraction over processes within a guest OS.
60pub trait VmiOsProcess<'a, Driver>: VmiVa + 'a
61where
62    Driver: VmiDriver,
63{
64    /// The VMI OS type.
65    type Os: VmiOs<Driver = Driver, Process<'a> = Self>;
66
67    /// Returns the process ID.
68    fn id(&self) -> Result<ProcessId, VmiError>;
69
70    /// Returns the process object.
71    fn object(&self) -> Result<ProcessObject, VmiError>;
72
73    /// Returns the name of the process.
74    ///
75    /// # Platform-specific
76    ///
77    /// - **Windows**: `_EPROCESS.ImageFileName` (limited to 16 characters).
78    /// - **Linux**: `_task_struct.comm` (limited to 16 characters).
79    fn name(&self) -> Result<String, VmiError>;
80
81    /// Returns the parent process ID.
82    fn parent_id(&self) -> Result<ProcessId, VmiError>;
83
84    /// Returns the architecture of the process.
85    fn architecture(&self) -> Result<VmiOsImageArchitecture, VmiError>;
86
87    /// Returns the process's page table translation root.
88    fn translation_root(&self) -> Result<Pa, VmiError>;
89
90    /// Returns the user-mode page table translation root.
91    ///
92    /// If KPTI is disabled, this function will return the same value as
93    /// [`translation_root`](Self::translation_root).
94    fn user_translation_root(&self) -> Result<Pa, VmiError>;
95
96    /// Returns the base address of the process image.
97    fn image_base(&self) -> Result<Va, VmiError>;
98
99    /// Returns an iterator over the process's memory regions.
100    fn regions(
101        &self,
102    ) -> Result<
103        impl Iterator<Item = Result<<Self::Os as VmiOs>::Region<'a>, VmiError>> + use<'a, Driver, Self>,
104        VmiError,
105    >;
106
107    /// Returns the memory region containing the given address.
108    fn lookup_region(
109        &self,
110        address: Va,
111    ) -> Result<Option<<Self::Os as VmiOs>::Region<'a>>, VmiError>;
112
113    /// Returns an iterator over the threads in the process.
114    ///
115    /// # Platform-specific
116    ///
117    /// - **Windows**: `_EPROCESS.ThreadListHead`.
118    fn threads(
119        &self,
120    ) -> Result<
121        impl Iterator<Item = Result<<Self::Os as VmiOs>::Thread<'a>, VmiError>> + use<'a, Driver, Self>,
122        VmiError,
123    >;
124
125    /// Checks whether the given virtual address is valid in the process.
126    ///
127    /// This method checks if page-faulting on the address would result in
128    /// a successful access.
129    fn is_valid_address(&self, address: Va) -> Result<Option<bool>, VmiError>;
130}
131
132/// Extension methods on [`VmiOsProcess`].
133///
134/// The blanket impl is the only impl of this trait, so implementors of
135/// [`VmiOsProcess`] cannot override the default bodies.
136pub trait VmiOsProcessExt<'a, Driver>: VmiOsProcess<'a, Driver>
137where
138    Driver: VmiDriver,
139{
140    /// Returns the first memory region matching `predicate`, or
141    /// `Ok(None)` if no region in the process matches.
142    fn find_region(
143        &self,
144        predicate: impl RegionPredicate<Self::Os>,
145    ) -> Result<Option<<Self::Os as VmiOs>::Region<'a>>, VmiError> {
146        for region in self.regions()? {
147            let region = region?;
148
149            if predicate.matches(&region)? {
150                return Ok(Some(region));
151            }
152        }
153
154        Ok(None)
155    }
156
157    /// Returns an iterator over the memory regions matching `predicate`.
158    fn filter_regions(
159        &self,
160        predicate: impl RegionPredicate<Self::Os>,
161    ) -> Result<impl Iterator<Item = Result<<Self::Os as VmiOs>::Region<'a>, VmiError>>, VmiError>
162    {
163        let mut regions = self.regions()?;
164
165        Ok(std::iter::from_fn(move || {
166            for region in regions.by_ref() {
167                let region = match region {
168                    Ok(region) => region,
169                    Err(err) => return Some(Err(err)),
170                };
171
172                match predicate.matches(&region) {
173                    Ok(true) => return Some(Ok(region)),
174                    Ok(false) => continue,
175                    Err(err) => return Some(Err(err)),
176                }
177            }
178
179            None
180        }))
181    }
182}
183
184impl<'a, Driver, T> VmiOsProcessExt<'a, Driver> for T
185where
186    Driver: VmiDriver,
187    T: VmiOsProcess<'a, Driver>,
188{
189}