{
  "finding_id": "DF-5015",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "dos",
  "confidence": "certain",
  "verdict": "Reproduced: an unprivileged console user (uid 65534 after fd open) shrinks a syscons history ring to 25 rows via ioctl(CONS_HISTORY,25) on an 80x25 vty; a mode change to 80x60 updates scp->xsize/ysize BEFORE sc_alloc_history_buffer() runs, and when that realloc fails (M_NOWAIT under kernel memory pressure, reproduced via unpriv churn) its return is ignored (scvidctl.c:163/397/947) and the failure path re-installs the stale 2000-cell ring against a 4800-cell screen. The mismatch was reproduced three times with a user-visible artifact (scroll-lock+End view shows the marker line 2-3x: ring wrap) and confirmed in-kernel with a KLD probe (sysctl hw.df5015: rows=25 size=2000 ... ysize=60). Scroll-lock exit runs sc_hist_restore() whose sc_vtb_pos(tail,-xsize*ysize) is negative for every tail in this configuration; the subsequent sc_hist_save() append executed on the armed ring (observed via ring-content views). Impact is recorded as dos because the directly-observed manifestation is history/scrollback corruption; the write primitive itself (up to 4000 bytes of attacker-typed screen text BEFORE the ring, plus an OOB read past it when columns misalign) executed per the code path but no independent crash/leak artifact was pinned to it in isolation - a kernel write fault in sc_vtb_bcopy during the same campaign is attributed to DF-5016s UAF (no keyboard was active in that run). A generic DragonFly ioctl-loop token assertion (reproducible with TIOCGWINSZ alone) was identified and excluded as a confound.",
  "exploit_chain": "console-seat fd -> ioctl(CONS_HISTORY,25) -> ioctl(CONS_SET, 80x60) during kmem pressure (realloc fails, geometry already updated) -> scroll-lock in/out (sc_hist_restore stores negative vtb_tail) -> any scrolled line/mode change appends up to 4000 bytes of controlled screen text before the 4000-byte M_SYSCONS ring (kmem-obj heap underflow write; repeatable); column-mismatched variants OOB-read heap to the visible screen. uid=0 not achieved (needs deterministic alloc-failure window + heap grooming; documented in VERDICT.md).",
  "evidence": "README.md/VERDICT.md; df5015.c (trigger tool); round2.py-round6.py transcripts in run logs; marker wrap artifacts [3,34,59]/[28,59] (hunt detections); offmod2.c in-kernel probe output rows=25 size=2000 ... ysize=60; panic-scvtb_bcopy-unpriv-churn.log (campaign write fault); fix.diff (validated build)",
  "kernel_refs": [
    "sys/dev/misc/syscons/schistory.c:118-160",
    "sys/dev/misc/syscons/schistory.c:211-215",
    "sys/dev/misc/syscons/schistory.c:219-234",
    "sys/dev/misc/syscons/schistory.c:244-259",
    "sys/dev/misc/syscons/scvtb.c:183-186",
    "sys/dev/misc/syscons/scvtb.c:221-235",
    "sys/dev/misc/syscons/scvtb.c:239-242",
    "sys/dev/misc/syscons/scvtb.c:198-211",
    "sys/dev/misc/syscons/scvidctl.c:146-163",
    "sys/dev/misc/syscons/scvidctl.c:382-397",
    "sys/dev/misc/syscons/syscons.c:3843-3933"
  ],
  "poc_changes": "rewrote trigger from scratch: CONS_HISTORY/CONS_SET/CONS_SCRSHOT/TIOCGWINSZ/KDGKBSTATE/VT_ACTIVATE plumbing (by-value ioctl args), QEMU-monitor key injection with hardware SLK-state sync, in-kernel KLD probe instead of /dev/kmem (pread rejects kernel-canonical addresses and blind kmem scans fault), pressure redesigned several times (pipe writes block; tmpfs/anon bursts work)",
  "attempts": 9,
  "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": 9600,
  "guest_dirty": 0,
  "build_cmd": "cc -O1 -o /tmp/df5015 /tmp/df5015.c (guest)",
  "run_cmd": "./df5015 arm; pressure churn; ./df5015 flip 100000 3000 60 &; monitor sendkey scroll_lock/end; ./df5015 shot 0 (mismatch detect); scroll_lock in/out cycles (arm+fire)",
  "code_hash": "0e529d3f69c203058bbcd187072ab0747ee877543e785672b55dd5aee1f3cff1",
  "notes": "generic DragonFly issue found while verifying: ANY tight unpriv ioctl loop on a tty (even TIOCGWINSZ) panics with assertion count & TOK_COUNTMASK failed in _lwkt_reltokref within ~60-90s (stock kernel, 4/4) - NOT a syscons bug; route to a kern/lwkt audit. offmod/scan-tool panics in the pack are my own tooling faults, documented.",
  "recommended_fix": "On sc_alloc_history_buffer failure free the stale-geometry ring and leave scp->history NULL (callers/CONS_CLRHIST already NULL-guard or must be taught to); see fix.diff",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff applied to guest /usr/src; patched X86_64_GENERIC compiled, installed and booted (KBUILD_DONE, kernel #1 Sat Sep 26 01:40). The stale-geometry state is eliminated by construction (failure path frees the ring and installs NULL; browse/CLRHIST guard). Full re-trigger of the alloc-failure precondition on the patched kernel was not re-run to completion (precondition is a stochastic NOWAIT failure window); patched kernel survived CONS_HISTORY/mode-change churn and normal syscons function.",
  "fix_evidence": "/tmp/kbuild.log KBUILD_DONE + installkernel completion in transcript; fix.diff in pack"
}