Skip to main content

vmi_os_windows/iter/
list.rs

1use std::iter::FusedIterator;
2
3use vmi_core::{Pa, Registers as _, Va, VmiError, VmiState, driver::VmiRead};
4
5use crate::{
6    WindowsOs, WindowsWow64Kind,
7    arch::{ArchAdapter, StructLayout, StructLayout32, StructLayout64},
8};
9
10/// Field offsets for a `LIST_ENTRY` structure.
11pub trait ListEntry<Layout>
12where
13    Layout: StructLayout,
14{
15    /// Offset of the `LIST_ENTRY::Flink` field.
16    const OFFSET_FLINK: u64;
17
18    /// Offset of the `LIST_ENTRY::Blink` field.
19    const OFFSET_BLINK: u64;
20}
21
22/// `LIST_ENTRY` structure layout.
23pub struct ListEntryLayout;
24
25impl ListEntry<StructLayout32> for ListEntryLayout {
26    const OFFSET_FLINK: u64 = 0x00;
27    const OFFSET_BLINK: u64 = 0x04;
28}
29
30impl ListEntry<StructLayout64> for ListEntryLayout {
31    const OFFSET_FLINK: u64 = 0x00;
32    const OFFSET_BLINK: u64 = 0x08;
33}
34
35/// Iterator over a `LIST_ENTRY` chain with a compile-time pointer width.
36///
37/// Generic over [`StructLayout`], so it is monomorphized for either
38/// 32-bit or 64-bit structures. Prefer [`ListEntryIterator`] when the
39/// pointer width is not known at compile time.
40pub struct ListEntryIteratorBase<'a, Driver, Layout>
41where
42    Driver: VmiRead,
43    Driver::Architecture: ArchAdapter<Driver>,
44    Layout: StructLayout,
45    ListEntryLayout: ListEntry<Layout>,
46{
47    /// VMI state.
48    vmi: VmiState<'a, WindowsOs<Driver>>,
49
50    /// Address of the list head.
51    list_head: Va,
52
53    /// Offset to the containing structure.
54    ///
55    /// The offset is subtracted from the entry address to get the containing
56    /// structure, similar to the `CONTAINING_RECORD` macro in the Windows
57    /// kernel.
58    offset: u64,
59
60    /// The translation root.
61    root: Pa,
62
63    /// Current entry.
64    current: Option<Va>,
65
66    /// Whether the iterator has been initialized.
67    initialized: bool,
68
69    _marker: std::marker::PhantomData<Layout>,
70}
71
72impl<'a, Driver, Layout> ListEntryIteratorBase<'a, Driver, Layout>
73where
74    Driver: VmiRead,
75    Driver::Architecture: ArchAdapter<Driver>,
76    Layout: StructLayout,
77    ListEntryLayout: ListEntry<Layout>,
78{
79    /// Creates a new list entry iterator.
80    pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, list_head: Va, offset: u64, root: Pa) -> Self {
81        Self {
82            vmi,
83            list_head,
84            offset,
85            root,
86            current: None,
87            initialized: false,
88            _marker: std::marker::PhantomData,
89        }
90    }
91
92    /// Returns the next entry in the list.
93    ///
94    /// Corresponds to the `LIST_ENTRY.Flink` pointer.
95    fn next_entry(&self, entry: Va) -> Result<Va, VmiError> {
96        Layout::read_va(
97            self.vmi,
98            (
99                entry + <ListEntryLayout as ListEntry<Layout>>::OFFSET_FLINK,
100                self.root,
101            ),
102        )
103    }
104
105    /// Returns the previous entry in the list.
106    ///
107    /// Corresponds to the `LIST_ENTRY.Blink` pointer.
108    fn previous_entry(&self, entry: Va) -> Result<Va, VmiError> {
109        Layout::read_va(
110            self.vmi,
111            (
112                entry + <ListEntryLayout as ListEntry<Layout>>::OFFSET_BLINK,
113                self.root,
114            ),
115        )
116    }
117
118    /// Returns the first entry in the list.
119    ///
120    /// Returns `None` if the `list_head` is `NULL`.
121    fn first_entry(&self) -> Result<Option<Va>, VmiError> {
122        if self.list_head.is_null() {
123            return Ok(None);
124        }
125
126        Ok(Some(self.next_entry(self.list_head)?))
127    }
128
129    /// Returns the last entry in the list.
130    ///
131    /// Returns `None` if the `list_head` is `NULL`.
132    fn last_entry(&self) -> Result<Option<Va>, VmiError> {
133        if self.list_head.is_null() {
134            return Ok(None);
135        }
136
137        Ok(Some(self.previous_entry(self.list_head)?))
138    }
139
140    /// Walks to the next entry in the list.
141    fn walk_next(&mut self) -> Result<Option<Va>, VmiError> {
142        let entry = match self.current {
143            Some(entry) => entry,
144            None => {
145                // If `self.current` is `None`, we need to initialize the iterator.
146                //
147                // However, if the iterator has already been initialized, we should
148                // return `None` to prevent infinite iteration.
149                if self.initialized {
150                    return Ok(None);
151                }
152
153                self.initialized = true;
154
155                match self.first_entry() {
156                    Ok(Some(first)) => first,
157                    Ok(None) => return Ok(None),
158                    Err(err) => return Err(err),
159                }
160            }
161        };
162
163        if entry == self.list_head {
164            return Ok(None);
165        }
166
167        match self.next_entry(entry) {
168            Ok(next) => self.current = Some(next),
169            Err(err) => {
170                // Terminate iteration so that callers who `continue` on
171                // errors do not spin forever on the same failing entry.
172                self.current = None;
173                return Err(err);
174            }
175        }
176
177        Ok(Some(entry - self.offset))
178    }
179
180    /// Walks to the previous entry in the list.
181    fn walk_next_back(&mut self) -> Result<Option<Va>, VmiError> {
182        let entry = match self.current {
183            Some(entry) => entry,
184            None => {
185                // If `self.current` is `None`, we need to initialize the iterator.
186                //
187                // However, if the iterator has already been initialized, we should
188                // return `None` to prevent infinite iteration.
189                if self.initialized {
190                    return Ok(None);
191                }
192
193                self.initialized = true;
194
195                match self.last_entry() {
196                    Ok(Some(last)) => last,
197                    Ok(None) => return Ok(None),
198                    Err(err) => return Err(err),
199                }
200            }
201        };
202
203        if entry == self.list_head {
204            return Ok(None);
205        }
206
207        match self.previous_entry(entry) {
208            Ok(prev) => self.current = Some(prev),
209            Err(err) => {
210                self.current = None;
211                return Err(err);
212            }
213        }
214
215        Ok(Some(entry - self.offset))
216    }
217}
218
219impl<Driver, Layout> Iterator for ListEntryIteratorBase<'_, Driver, Layout>
220where
221    Driver: VmiRead,
222    Driver::Architecture: ArchAdapter<Driver>,
223    Layout: StructLayout,
224    ListEntryLayout: ListEntry<Layout>,
225{
226    type Item = Result<Va, VmiError>;
227
228    fn next(&mut self) -> Option<Self::Item> {
229        self.walk_next().transpose()
230    }
231}
232
233impl<Driver, Layout> DoubleEndedIterator for ListEntryIteratorBase<'_, Driver, Layout>
234where
235    Driver: VmiRead,
236    Driver::Architecture: ArchAdapter<Driver>,
237    Layout: StructLayout,
238    ListEntryLayout: ListEntry<Layout>,
239{
240    fn next_back(&mut self) -> Option<Self::Item> {
241        self.walk_next_back().transpose()
242    }
243}
244
245impl<Driver, Layout> FusedIterator for ListEntryIteratorBase<'_, Driver, Layout>
246where
247    Driver: VmiRead,
248    Driver::Architecture: ArchAdapter<Driver>,
249    Layout: StructLayout,
250    ListEntryLayout: ListEntry<Layout>,
251{
252}
253
254enum ListEntryWrapper<'a, Driver>
255where
256    Driver: VmiRead,
257    Driver::Architecture: ArchAdapter<Driver>,
258{
259    W32(ListEntryIteratorBase<'a, Driver, StructLayout32>),
260    W64(ListEntryIteratorBase<'a, Driver, StructLayout64>),
261}
262
263impl<'a, Driver> ListEntryWrapper<'a, Driver>
264where
265    Driver: VmiRead,
266    Driver::Architecture: ArchAdapter<Driver>,
267{
268    fn w32(vmi: VmiState<'a, WindowsOs<Driver>>, list_head: Va, offset: u64, root: Pa) -> Self {
269        Self::W32(ListEntryIteratorBase::new(vmi, list_head, offset, root))
270    }
271
272    fn w64(vmi: VmiState<'a, WindowsOs<Driver>>, list_head: Va, offset: u64, root: Pa) -> Self {
273        Self::W64(ListEntryIteratorBase::new(vmi, list_head, offset, root))
274    }
275
276    fn native(vmi: VmiState<'a, WindowsOs<Driver>>, list_head: Va, offset: u64, root: Pa) -> Self {
277        match vmi.registers().address_width() {
278            4 => Self::w32(vmi, list_head, offset, root),
279            8 => Self::w64(vmi, list_head, offset, root),
280            _ => panic!("Unsupported address width"),
281        }
282    }
283
284    fn walk_next(&mut self) -> Result<Option<Va>, VmiError> {
285        match self {
286            Self::W32(inner) => inner.walk_next(),
287            Self::W64(inner) => inner.walk_next(),
288        }
289    }
290
291    fn walk_next_back(&mut self) -> Result<Option<Va>, VmiError> {
292        match self {
293            Self::W32(inner) => inner.walk_next_back(),
294            Self::W64(inner) => inner.walk_next_back(),
295        }
296    }
297}
298
299/// Iterator over a `LIST_ENTRY` chain with a runtime pointer width.
300///
301/// Wraps [`ListEntryIteratorBase`] and erases the [`StructLayout`] type
302/// parameter, dispatching between 32-bit and 64-bit layouts dynamically.
303pub struct ListEntryIterator<'a, Driver>
304where
305    Driver: VmiRead,
306    Driver::Architecture: ArchAdapter<Driver>,
307{
308    inner: ListEntryWrapper<'a, Driver>,
309}
310
311impl<'a, Driver> From<ListEntryIteratorBase<'a, Driver, StructLayout32>>
312    for ListEntryIterator<'a, Driver>
313where
314    Driver: VmiRead,
315    Driver::Architecture: ArchAdapter<Driver>,
316{
317    fn from(value: ListEntryIteratorBase<'a, Driver, StructLayout32>) -> Self {
318        Self {
319            inner: ListEntryWrapper::W32(value),
320        }
321    }
322}
323
324impl<'a, Driver> From<ListEntryIteratorBase<'a, Driver, StructLayout64>>
325    for ListEntryIterator<'a, Driver>
326where
327    Driver: VmiRead,
328    Driver::Architecture: ArchAdapter<Driver>,
329{
330    fn from(value: ListEntryIteratorBase<'a, Driver, StructLayout64>) -> Self {
331        Self {
332            inner: ListEntryWrapper::W64(value),
333        }
334    }
335}
336
337impl<'a, Driver> ListEntryIterator<'a, Driver>
338where
339    Driver: VmiRead,
340    Driver::Architecture: ArchAdapter<Driver>,
341{
342    /// Creates a new list entry iterator.
343    pub fn new(vmi: VmiState<'a, WindowsOs<Driver>>, list_head: Va, offset: u64) -> Self {
344        Self::with_kind(
345            vmi,
346            list_head,
347            offset,
348            vmi.translation_root(list_head),
349            WindowsWow64Kind::Native,
350        )
351    }
352
353    /// Creates a new list entry iterator with an explicit address space
354    /// root and pointer width.
355    pub fn with_kind(
356        vmi: VmiState<'a, WindowsOs<Driver>>,
357        list_head: Va,
358        offset: u64,
359        root: Pa,
360        kind: WindowsWow64Kind,
361    ) -> Self {
362        let inner = match kind {
363            WindowsWow64Kind::Native => ListEntryWrapper::native(vmi, list_head, offset, root),
364            WindowsWow64Kind::X86 => ListEntryWrapper::w32(vmi, list_head, offset, root),
365        };
366
367        Self { inner }
368    }
369
370    /// Walks to the next entry in the list.
371    fn walk_next(&mut self) -> Result<Option<Va>, VmiError> {
372        self.inner.walk_next()
373    }
374
375    /// Walks to the previous entry in the list.
376    fn walk_next_back(&mut self) -> Result<Option<Va>, VmiError> {
377        self.inner.walk_next_back()
378    }
379}
380
381impl<Driver> Iterator for ListEntryIterator<'_, Driver>
382where
383    Driver: VmiRead,
384    Driver::Architecture: ArchAdapter<Driver>,
385{
386    type Item = Result<Va, VmiError>;
387
388    fn next(&mut self) -> Option<Self::Item> {
389        self.walk_next().transpose()
390    }
391}
392
393impl<Driver> DoubleEndedIterator for ListEntryIterator<'_, Driver>
394where
395    Driver: VmiRead,
396    Driver::Architecture: ArchAdapter<Driver>,
397{
398    fn next_back(&mut self) -> Option<Self::Item> {
399        self.walk_next_back().transpose()
400    }
401}
402
403impl<Driver> FusedIterator for ListEntryIterator<'_, Driver>
404where
405    Driver: VmiRead,
406    Driver::Architecture: ArchAdapter<Driver>,
407{
408}