Snake movement engine confines itself purely by wall-bounce arithmetic writing through the completely unchecked sc_vtb_putc: any geometry inconsistency escapes and runs away with unbounded 2-byte OOB writes marching through the video window into adjacent DMAP'd memory (latent β no in-tree path produces the trigger)
Summary
The bounce conditions are the ONLY confinement over a raw unchecked *(vtb_buffer+at) store - ysize==1 geometry escapes deterministically (C truncated division prevents recovery) and each tick OOB-writes video-aperture cells at ~50B/s into DMAP'd low RAM. Latent (CONS_SET always full-dims; geometry changes unblank first); the sim proves the exact kernel arithmetic. Head-validate-and-reinit fix + bounds-check sc_vtb_putc defense-in-depth.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5194 Β· 12 files| File | Type | Description | Size | |
|---|---|---|---|---|
| sim.c | β | 2.2 KB | view raw | |
| sim.log | β | 622 B | view raw | |
| snake_probe.c | β | 3.7 KB | view raw | |
| guard_probe.c | β | 2.9 KB | view raw | |
| build.sh | β | 66 B | view raw | |
| run.sh | β | 172 B | view raw | |
| build.log | β | 9 B | view raw | |
| run.log | β | 1.5 KB | view raw | |
| run.live.log | β | 1.1 KB | view raw | |
| fix.diff | β | 990 B | view raw | |
| verdict.json | β | 3.8 KB | view raw | |
| env.txt | β | 594 B | view raw |
Fix verification
not_testableLatent 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.diff; sim.log demonstrates the clamped behavior class (in-bounds runs)
Confirmed kernel references
- 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
Detail
Evidence (decisive lines)
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).
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.
Verified 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().
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 module's '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).
No comments yet.