Skip to content

Commit b46fc5d

Browse files
committed
paging: make ALL levels writable, not just P4
1 parent 7a8c54b commit b46fc5d

1 file changed

Lines changed: 49 additions & 20 deletions

File tree

src/arch/x86_64/mm/paging.rs

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -325,25 +325,6 @@ fn make_p4_writable() {
325325

326326
let mut pt = unsafe { identity_mapped_page_table() };
327327

328-
let p4_page = {
329-
let (p4_frame, _) = Cr3::read_raw();
330-
let p4_addr = x86_64::VirtAddr::new(p4_frame.start_address().as_u64());
331-
Page::<Size4KiB>::from_start_address(p4_addr).unwrap()
332-
};
333-
334-
let TranslateResult::Mapped { frame, flags, .. } = pt.translate(p4_page.start_address()) else {
335-
unreachable!()
336-
};
337-
338-
let make_writable = || unsafe {
339-
let flags = flags | PageTableEntryFlags::WRITABLE;
340-
match frame {
341-
MappedFrame::Size1GiB(_) => pt.set_flags_p3_entry(p4_page, flags).unwrap().ignore(),
342-
MappedFrame::Size2MiB(_) => pt.set_flags_p2_entry(p4_page, flags).unwrap().ignore(),
343-
MappedFrame::Size4KiB(_) => pt.update_flags(p4_page, flags).unwrap().ignore(),
344-
}
345-
};
346-
347328
unsafe fn without_protect<F, R>(f: F) -> R
348329
where
349330
F: FnOnce() -> R,
@@ -359,7 +340,55 @@ fn make_p4_writable() {
359340
ret
360341
}
361342

362-
unsafe { without_protect(make_writable) }
343+
let (p4_frame, _) = Cr3::read_raw();
344+
unsafe {
345+
without_protect(|| make_page_table_writable(&mut pt, p4_frame, 4));
346+
};
347+
}
348+
349+
unsafe fn make_page_table_writable(
350+
page_table: &mut OffsetPageTable<'static>,
351+
pt_frame: PhysFrame,
352+
level: u8,
353+
) {
354+
let pt_address = page_table.phys_offset() + pt_frame.start_address().as_u64();
355+
let pt = unsafe { pt_address.as_ptr::<PageTable>().as_ref().unwrap() };
356+
357+
// Unmap the page table
358+
let TranslateResult::Mapped { frame, flags, .. } = page_table.translate(pt_address) else {
359+
unreachable!()
360+
};
361+
362+
if !flags.contains(PageTableEntryFlags::WRITABLE) {
363+
let flags = flags | PageTableEntryFlags::WRITABLE;
364+
let page = Page::<Size4KiB>::containing_address(pt_address);
365+
unsafe {
366+
match frame {
367+
MappedFrame::Size1GiB(_) => {
368+
page_table.set_flags_p3_entry(page, flags).unwrap().ignore()
369+
}
370+
MappedFrame::Size2MiB(_) => {
371+
page_table.set_flags_p2_entry(page, flags).unwrap().ignore()
372+
}
373+
MappedFrame::Size4KiB(_) => page_table.update_flags(page, flags).unwrap().ignore(),
374+
}
375+
}
376+
warn!("Page table {pt_frame:x?}, was mapped from RO memory!");
377+
}
378+
379+
for entry in pt.iter() {
380+
if entry.is_unused() {
381+
continue;
382+
}
383+
384+
let is_page_table = level > 1 && !entry.flags().contains(PageTableEntryFlags::HUGE_PAGE);
385+
if is_page_table {
386+
let phys = entry.frame().unwrap();
387+
unsafe {
388+
make_page_table_writable(page_table, phys, level - 1);
389+
}
390+
}
391+
}
363392
}
364393

365394
pub unsafe fn log_page_tables() {

0 commit comments

Comments
 (0)