diff options
| author | salmonik <salmonik@tuta.io> | 2026-08-02 23:13:46 +0200 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-08-02 23:13:46 +0200 |
| commit | c10eb2333f277f815234f9fc26a5441e68ef7b40 (patch) | |
| tree | 9bff5b38a21c7edfa997a25a0ee51cb43c570a68 /rsdos/src | |
| parent | v0.5.7: guard report 4-words-per-line — 16 stack words survive band hand-copy (diff) | |
| download | rs-dos-c10eb2333f277f815234f9fc26a5441e68ef7b40.tar.gz rs-dos-c10eb2333f277f815234f9fc26a5441e68ef7b40.zip | |
v0.5.7: guard reports the drop's size/align — identifies the clobbered struct
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.
Diffstat (limited to 'rsdos/src')
| -rw-r--r-- | rsdos/src/main.rs | 25 |
1 files changed, 17 insertions, 8 deletions
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 | |||
| 352 | // visible on QEMU (serial + gdb available) instead of only on the | 352 | // visible on QEMU (serial + gdb available) instead of only on the |
| 353 | // OptiPlex. | 353 | // OptiPlex. |
| 354 | stack_fill_aa(); | 354 | stack_fill_aa(); |
| 355 | // Poison the free heap AND the free pages with the OptiPlex's | ||
| 356 | // 0x00AAAAAA scrub pattern — the firmware's leftover fills both the | ||
| 357 | // heap (freed pool) and the pages the allocators hand out (heap | ||
| 358 | // growth, task stacks). Together with the stack fill this makes | ||
| 359 | // any uninitialized read reproduce the real machine's crashes in | ||
| 360 | // QEMU (garbage sizes → alloc panics, garbage ptrs → dealloc guard). | ||
| 361 | rsnix::memory::poison_free_blocks_aa(); | ||
| 362 | rsnix::memory::poison_free_pages_aa(); | ||
| 355 | shell::run(); | 363 | shell::run(); |
| 356 | } | 364 | } |
| 357 | 365 | ||
| 358 | /// Write 0xAA over the stack region the shell's frames will reuse, | 366 | /// Write the OptiPlex's 0x00AAAAAA scrub pattern over the stack region |
| 359 | /// leaving the current frames (top 4 KiB) intact. 128 KiB covers the | 367 | /// the shell's frames will reuse, leaving only 256 B of live frame |
| 360 | /// whole shell frame chain on QEMU and the OptiPlex. Best-effort: the | 368 | /// headroom. 128 KiB covers the whole shell frame chain on QEMU and |
| 361 | /// region is below rsp inside the boot stack mapping. | 369 | /// the OptiPlex. Best-effort: the region is below rsp inside the boot |
| 370 | /// stack mapping; the call into `shell::run` overwrites the top word. | ||
| 362 | fn stack_fill_aa() { | 371 | fn stack_fill_aa() { |
| 363 | let rsp: usize; | 372 | let rsp: usize; |
| 364 | unsafe { | 373 | unsafe { |
| 365 | core::arch::asm!("mov {}, rsp", out(reg) rsp); | 374 | core::arch::asm!("mov {}, rsp", out(reg) rsp); |
| 366 | } | 375 | } |
| 367 | let top = rsp - 0x1000; | 376 | let top = rsp - 0x100; |
| 368 | let bottom = rsp - 0x21000; | 377 | let bottom = rsp - 0x21100; |
| 369 | unsafe { | 378 | unsafe { |
| 370 | let mut p = bottom; | 379 | let mut p = bottom; |
| 371 | while p < top { | 380 | while p < top { |
| 372 | core::ptr::write_volatile(p as *mut u64, 0xAAAAAAAAAAAAAAAA); | 381 | core::ptr::write_volatile(p as *mut u64, 0x00AAAAAA00AAAAAA); |
| 373 | p += 8; | 382 | p += 8; |
| 374 | } | 383 | } |
| 375 | } | 384 | } |
| 376 | rsnix::serial_println!("stack: 0xAA-fill 0x{:x}..0x{:x}", bottom, top); | 385 | rsnix::serial_println!("stack: 0x00AAAAAA-fill 0x{:x}..0x{:x}", bottom, top); |
| 377 | } | 386 | } |
| 378 | 387 | ||
| 379 | // --------------------------------------------------------------------------- | 388 | // --------------------------------------------------------------------------- |
