From 0187b802113a10a9ee99af48b811cd332c660a13 Mon Sep 17 00:00:00 2001 From: salmonik Date: Sun, 2 Aug 2026 21:47:18 +0200 Subject: v0.5.7: allocator corruption guard + full register dump for real-hardware repro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The OptiPlex #GP (vec=13 in __rust_dealloc) frees a garbage pointer: the back-pointer at [ptr-8] is clobbered by the time the shell drops its Parsed struct. A blind store to the bogus block header was an opaque #GP — now it is a readable report: - dealloc validates the back-pointer (in-heap block, sane size, in-use) before trusting it; on failure it prints ptr/block/heap range, the memory around the block header, and the live stack chain, writes the crash band + crash.log, and halts (memory.rs: heap_guard_report). - fault dumps now carry the full register set (rax..rdi, rbx, r8..r15) so the next repro shows the exact freed ptr and clobbered value. - new 'corrupt' shell hook deliberately clobbers a live block's back-pointer to prove the guard fires (test-fault-style halt). Verified: test-msg/test-disk/test-fault pass; corrupt hook reports ptr=.. block=0xdeedbeef... with mem dump instead of #GP. rs-dos.img rebuilt with the release kernel. --- rsnix/src/sched.rs | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'rsnix/src/sched.rs') diff --git a/rsnix/src/sched.rs b/rsnix/src/sched.rs index a31ea6e..dd1409e 100644 --- a/rsnix/src/sched.rs +++ b/rsnix/src/sched.rs @@ -730,7 +730,49 @@ pub(crate) fn fault_dump(kind: &str, cr2: u64, frame: &crate::interrupts::IntFra let l2 = core::str::from_utf8(&b2[..n2]).unwrap_or(""); let l3 = core::str::from_utf8(&b3[..n3]).unwrap_or(""); let l4 = core::str::from_utf8(&b4[..n4]).unwrap_or("bt=?"); - let lines = [l1, l2, l3, l4]; + + // Register dump — the faulting register state, so a real-hardware + // repro can be diagnosed without serial. Two lines on screen (the + // band is clamped), full set in crash.log via `lines`. + let mut r1 = [0u8; 160]; + let rn1 = { + let mut w = crate::strbuf::FmtBuf::new(&mut r1); + let _ = fmt::write( + &mut w, + core::format_args!( + "rax={:#x} rcx={:#x} rdx={:#x} rsi={:#x} rdi={:#x}", + frame.rax, frame.rcx, frame.rdx, frame.rsi, frame.rdi + ), + ); + w.len() + }; + let mut r2 = [0u8; 160]; + let rn2 = { + let mut w = crate::strbuf::FmtBuf::new(&mut r2); + let _ = fmt::write( + &mut w, + core::format_args!( + "rbx={:#x} r8={:#x} r9={:#x} r10={:#x} r11={:#x} r12={:#x} r13={:#x} r14={:#x} r15={:#x}", + frame.rbx, + frame.r8, + frame.r9, + frame.r10, + frame.r11, + frame.r12, + frame.r13, + frame.r14, + frame.r15 + ), + ); + w.len() + }; + let l5 = core::str::from_utf8(&r1[..rn1]).unwrap_or(""); + let l6 = core::str::from_utf8(&r2[..rn2]).unwrap_or(""); + crate::serial::write_raw(l5); + crate::serial::write_raw("\r\n"); + crate::serial::write_raw(l6); + crate::serial::write_raw("\r\n"); + let lines = [l1, l2, l3, l4, l5, l6]; crate::gop::dump_lines(&lines); // Best-effort: persist the report to the disk so it survives the -- cgit v1.2.3