fix(os-linux): only forward exact whole-region munmaps to kfree - #36
Conversation
sys_munmap forwarded any (addr, len) straight to kfree, but the kernel heap only supports freeing the exact (pointer, layout) pairs it handed out, so POSIX-legal repeated, partial, or interior munmaps corrupted the free list or tripped the allocator's bad-free assert inside the trap handler, aborting the guest. musl std guests reach these paths through raw libc::munmap users and reservation trimming. Track the regions sys_mmap hands out in a fixed-capacity GlobalCell table (single-core, no interrupts, cooperative scheduling; same soundness argument as the scheduler's own state) and forward only a munmap whose base and page-rounded length exactly match a live entry; every other munmap keeps the pages mapped (a bounded leak, since a kmalloc-backed region cannot be partially returned) and reports success per POSIX. If the table fills, sys_mmap frees the fresh region and fails with -ENOMEM rather than handing out a mapping whose unmap could never be validated.
PR SummaryMedium Risk Overview
Adds unit tests for Reviewed by Cursor Bugbot for commit bf25245. Bugbot is set up for automated code reviews on this repo. Configure here. |
Summary
sys_munmapcurrently forwards any guest(addr, len)straight tokfree. The kernel heap only supports freeing the exact(pointer, layout)pairs it handed out, so a POSIX-legal partial, interior, spanning, or repeated unmap corrupts the heap free list or trips the allocator's bad-free assert.crates/zeroos-os-linux/src/handlers/memory.rs) thatsys_mmaprecords into andsys_munmapconsults:kfreeis only called when(addr, len)exactly matches a live region. Every other unmap shape keeps the pages mapped (a bounded leak, since a kmalloc-backed region can't be partially freed) and returns success, per POSIX.GlobalCell(unsynchronized), not a lock: ZeroOS runs single-core with no interrupts and no preemption, and scheduling is cooperative, so the table is never accessed concurrently — same reasoning already backing the scheduler's ownGlobalOptionstate.Context
Upstream ask from a16z/jolt#1822, which hit this via a guarded workaround in the Jolt SDK. Original patch and validation by @Acentelles; iterated during review to drop an initial
spin::Mutexin favor of theGlobalCellidiom already used elsewhere in this kernel.Test plan
cargo clippy -p zeroos-os-linux --target riscv64gc-unknown-linux-musl --no-default-features --features memory,vfs,scheduler,random -- -D warnings