Skip to content

Commit 9e0a8d1

Browse files
authored
Merge pull request #425 from Freax13/fix/overflow
add workaround for recursive page tables with recursive index 511
2 parents f49761b + 1e66b26 commit 9e0a8d1

File tree

2 files changed

+27
-4
lines changed

2 files changed

+27
-4
lines changed

src/structures/paging/mapper/recursive_page_table.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ impl<'a> RecursivePageTable<'a> {
4747
/// - The page table must be active, i.e. the CR3 register must contain its physical address.
4848
///
4949
/// Otherwise `Err(())` is returned.
50+
///
51+
/// ## Safety
52+
///
53+
/// Note that creating a `PageTable` with recursive index 511 is unsound
54+
/// because allocating the last byte of the address space can lead to pointer
55+
/// overflows and undefined behavior. For more details, see the discussions
56+
/// [on Zulip](https://rust-lang.zulipchat.com/#narrow/stream/136281-t-opsem/topic/end-of-address-space)
57+
/// and [in the `unsafe-code-guidelines ` repo]https://github.com/rust-lang/unsafe-code-guidelines/issues/420).
5058
#[inline]
5159
pub fn new(table: &'a mut PageTable) -> Result<Self, InvalidPageTable> {
5260
let page = Page::containing_address(VirtAddr::new(table as *const _ as u64));

src/structures/paging/page_table.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -209,27 +209,42 @@ impl PageTable {
209209
/// Clears all entries.
210210
#[inline]
211211
pub fn zero(&mut self) {
212-
for entry in self.entries.iter_mut() {
212+
for entry in self.iter_mut() {
213213
entry.set_unused();
214214
}
215215
}
216216

217217
/// Returns an iterator over the entries of the page table.
218218
#[inline]
219219
pub fn iter(&self) -> impl Iterator<Item = &PageTableEntry> {
220-
self.entries.iter()
220+
(0..512).map(move |i| &self.entries[i])
221221
}
222222

223223
/// Returns an iterator that allows modifying the entries of the page table.
224224
#[inline]
225225
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut PageTableEntry> {
226-
self.entries.iter_mut()
226+
// Note that we intentionally don't just return `self.entries.iter()`:
227+
// Some users may choose to create a reference to a page table at
228+
// `0xffff_ffff_ffff_f000`. This causes problems because calculating
229+
// the end pointer of the page tables causes an overflow. Therefore
230+
// creating page tables at that address is unsound and must be avoided.
231+
// Unfortunately creating such page tables is quite common when
232+
// recursive page tables are used, so we try to avoid calculating the
233+
// end pointer if possible. `core::slice::Iter` calculates the end
234+
// pointer to determine when it should stop yielding elements. Because
235+
// we want to avoid calculating the end pointer, we don't use
236+
// `core::slice::Iter`, we implement our own iterator that doesn't
237+
// calculate the end pointer. This doesn't make creating page tables at
238+
// that address sound, but it avoids some easy to trigger
239+
// miscompilations.
240+
let ptr = self.entries.as_mut_ptr();
241+
(0..512).map(move |i| unsafe { &mut *ptr.add(i) })
227242
}
228243

229244
/// Checks if the page table is empty (all entries are zero).
230245
#[inline]
231246
pub fn is_empty(&self) -> bool {
232-
self.entries.iter().all(|entry| entry.is_unused())
247+
self.iter().all(|entry| entry.is_unused())
233248
}
234249
}
235250

0 commit comments

Comments
 (0)