DF-5194 / verdict.json
{ "finding_id": "DF-5194", "status": "not_reproduced", "reproduced": false, "impact": "none", "confidence": "certain", "verdict": "The OOB itself is latent and was NOT reproduced on the guest -- by design of the finding. What was verified: (1) the escape arithmetic is real -- sim.c, using the exact kernel arithmetic from snake_saver.c:83-111, shows a deterministic escape and unbounded forward drift (+xsize per tick, max observed 14199 cells past an 80-cell vtb) for ysize==1 geometry, while all real geometries (80x25, 132x60, 100k ticks with the random dirx/diry flips) stay strictly in bounds; (2) the live mechanism works and stays in bounds: on a vidconsole boot with snake_saver.ko loaded, the snake drew exactly 24 non-space cells + 1 space (messagelen 25), moved each drawing tick, and all observed cell indices were < xsize*ysize (run.live.log); (3) no in-tree path can produce the triggering geometry: the only geometry-passing caller of sc_set_text_mode is CONS_SET with xsize=ysize=0 (scvidctl.c:515, clamped to full mode dims >= 80x25), and every geometry-change/VT-switch path unblanks the saver first via sc_clean_up, resetting the modules blanked and re-initializing savs[] on the next blank cycle. Bonus discovery from the trigger attempts: mode-change-while-blanked does not merely stay in bounds -- it deadlocks the kernel (reproduced separately as DF-5195 in syscons.c).", "exploit_chain": "", "evidence": "sim.log (escape vs in-bounds controls); run.live.log (live snake on the vidconsole guest: 24+1 cells, moving, in bounds); VERDICT.md (full code-path kill list); fix.diff (clamp).", "kernel_refs": [ "sys/dev/misc/syscons/snake/snake_saver.c:100", "sys/dev/misc/syscons/snake/snake_saver.c:109", "sys/dev/misc/syscons/snake/snake_saver.c:111", "sys/dev/misc/syscons/scvtb.c:163", "sys/dev/misc/syscons/scvidctl.c:94", "sys/dev/misc/syscons/scvidctl.c:515", "sys/dev/misc/syscons/syscons.c:4189", "sys/dev/misc/syscons/syscons.c:3536" ], "poc_changes": "seeded draft assumptions corrected: the screen-saver subsystem requires (a) a vidconsole kernel console (with the stock console=comconsole, splash_init() never runs and kldload only queues the decoder -- saver inert) and (b) CONS_SAVERSTART/CONS_BLANKTIME to force blanking; observation channel switched from CONS_SCRSHOT (reads scp->vtb, which the snake never touches) to raw VGA memory via /dev/mem at phys 0xB8000.", "attempts": 4, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 120, "guest_dirty": 0, "build_cmd": "cc -O2 -o sim sim.c", "run_cmd": "./sim (plus guest harnesses: snake_probe / guard_probe / watch2)", "code_hash": "084d9c3030e80cf0673938bdf0108e77fa6c3047261635b05ed25fa03d233091", "notes": "Latent Info finding, same tier as the dragon savers DF-5114. The escape write would land in VGA VRAM (va_window = DMAP KVA of phys 0xB8000, 32KB window) and, on the runaway, march into DMAPd low physical RAM (0xC0000+, ~50 bytes/s at 25 ticks/s) -- silent corruption of the ROM-shadow/kernel-image region on QEMU-style hosts, or a page-fault panic where the aperture is not DMAP-backed. Guest left clean (loader.conf restored, rebooted).", "recommended_fix": "After savs[0] += dirx + diry, validate 0 <= savs[0] < scp->xsize*scp->ysize and reinitialize (blanked = 0) when out of range; defense-in-depth: bounds-check sc_vtb_putc().", "fix_status": "not_testable", "fix_baseline_reproduced": false, "fix_patched_reproduced": false, "fix_verdict": "Latent finding: there is no triggerable baseline to validate a fix against (the escape is unreachable through in-tree ioctls). fix.diff authored as the hardening clamp; not built.", "fix_evidence": "fix.diff; sim.log demonstrates the clamped behavior class (in-bounds runs)" } |