From c10eb2333f277f815234f9fc26a5441e68ef7b40 Mon Sep 17 00:00:00 2001 From: salmonik Date: Sun, 2 Aug 2026 23:13:46 +0200 Subject: v0.5.7: guard reports the drop's size/align — identifies the clobbered struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The OptiPlex crashes free garbage (0xaaaaaa, 0xaaaaaa00aaaaaa) whose value is the firmware's 0x00AAAAAA scrub pattern left in stack/heap. The drop size/align (the dealloc layout) now prints on the band, so the next repro shows both the garbage ptr AND the size it was freed with — cap×elem_size pinpoints which struct's fields were clobbered. --- rsdos/src/main.rs | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'rsdos/src') diff --git a/rsdos/src/main.rs b/rsdos/src/main.rs index 806f150..52b37ec 100644 --- a/rsdos/src/main.rs +++ b/rsdos/src/main.rs @@ -352,28 +352,37 @@ pub unsafe extern "efiapi" fn efi_main(image_handle: Handle, system_table: *mut // visible on QEMU (serial + gdb available) instead of only on the // OptiPlex. stack_fill_aa(); + // Poison the free heap AND the free pages with the OptiPlex's + // 0x00AAAAAA scrub pattern — the firmware's leftover fills both the + // heap (freed pool) and the pages the allocators hand out (heap + // growth, task stacks). Together with the stack fill this makes + // any uninitialized read reproduce the real machine's crashes in + // QEMU (garbage sizes → alloc panics, garbage ptrs → dealloc guard). + rsnix::memory::poison_free_blocks_aa(); + rsnix::memory::poison_free_pages_aa(); shell::run(); } -/// Write 0xAA over the stack region the shell's frames will reuse, -/// leaving the current frames (top 4 KiB) intact. 128 KiB covers the -/// whole shell frame chain on QEMU and the OptiPlex. Best-effort: the -/// region is below rsp inside the boot stack mapping. +/// Write the OptiPlex's 0x00AAAAAA scrub pattern over the stack region +/// the shell's frames will reuse, leaving only 256 B of live frame +/// headroom. 128 KiB covers the whole shell frame chain on QEMU and +/// the OptiPlex. Best-effort: the region is below rsp inside the boot +/// stack mapping; the call into `shell::run` overwrites the top word. fn stack_fill_aa() { let rsp: usize; unsafe { core::arch::asm!("mov {}, rsp", out(reg) rsp); } - let top = rsp - 0x1000; - let bottom = rsp - 0x21000; + let top = rsp - 0x100; + let bottom = rsp - 0x21100; unsafe { let mut p = bottom; while p < top { - core::ptr::write_volatile(p as *mut u64, 0xAAAAAAAAAAAAAAAA); + core::ptr::write_volatile(p as *mut u64, 0x00AAAAAA00AAAAAA); p += 8; } } - rsnix::serial_println!("stack: 0xAA-fill 0x{:x}..0x{:x}", bottom, top); + rsnix::serial_println!("stack: 0x00AAAAAA-fill 0x{:x}..0x{:x}", bottom, top); } // --------------------------------------------------------------------------- -- cgit v1.2.3