summaryrefslogtreecommitdiffstats
path: root/rsdos/src
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-08-02 23:13:46 +0200
committersalmonik <salmonik@tuta.io>2026-08-02 23:13:46 +0200
commitc10eb2333f277f815234f9fc26a5441e68ef7b40 (patch)
tree9bff5b38a21c7edfa997a25a0ee51cb43c570a68 /rsdos/src
parentv0.5.7: guard report 4-words-per-line — 16 stack words survive band hand-copy (diff)
downloadrs-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 '')
-rw-r--r--rsdos/src/main.rs25
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.
362fn stack_fill_aa() { 371fn 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// ---------------------------------------------------------------------------