DF-4668 / verdict.json
{ "finding_id": "DF-4668", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "Unprivileged kernel NULL-deref panic reproduced on the stock 6.5-DEVELOPMENT guest: with snp.ko loaded, any user installs the snoop line discipline on a private pty via TIOCSETD (tty.c:1128 has no privilege check; ttyopen() never sets t_sc), and closing the tty runs snplclose -> snp_down(NULL) -> read at NULL+0x30 (snp_blen). Fatal trap 12, Stopped at snp_down+0x73: cmpq $0x1000,0x30(%rbx). Fixed kernel rebuilt with the guard in snplclose: identical run survives, exit=0, guest stays up.", "exploit_chain": "unprivileged user (uid 1001, no groups) -> TIOCSETD(own pty, disc 8=snooplinedisc) -> close(slave) -> ptsclose -> snplclose with t_sc==NULL -> snp_down(NULL) -> deterministic kernel panic (DoS). No privesc: the faulting pointer is a constant NULL.", "evidence": "panic.txt: fault virtual address = 0x30 + Stopped at snp_down+0x73: cmpq $0x1000,0x30(%rbx) (offset 0x30 = offsetof(struct snoop, snp_blen); $0x1000 = SNOOP_MINLEN). run.2.log: same trigger on patched kernel survives.", "kernel_refs": [ "sys/dev/misc/snp/snp.c:135", "sys/dev/misc/snp/snp.c:517", "sys/kern/tty.c:1128", "sys/kern/tty_conf.c:93", "sys/kern/tty_pty.c:406" ], "poc_changes": "Seed sketch fixed: (1) enumeration must distinguish l_open failure (nodisc slots 1-6) from ENXIO (t >= nlinesw) and confirm install via TIOCGETD - snp occupies slot 7/8, so the highest installing index is snooplinedisc; (2) include <libutil.h> (no <pty.h> on DFly) and link -lutil; (3) keep every switched pty open until the final close (closing earlier IS the trigger).", "attempts": 2, "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": 420, "guest_dirty": 0, "build_cmd": "cc -O1 -o /tmp/snp_disc /tmp/snp_disc.c -lutil", "run_cmd": "vm.sh run_root kldload snp (setup once); vm.sh run_user /tmp/snp_disc", "code_hash": "4426fb1ee058b6dc557520462555ce96fcc994ce323009a36450adf61ee4a770", "notes": "Module precondition: snp.ko is NOT in the stock kernel and /dev/snp* are 0600 root:wheel, but the trigger never touches /dev/snp - only TIOCSETD on the users own pty, so any local user panics the box once the module is loaded (watch(1)/admin kldload). Same trigger class as DF-1801 (which is device-open gated); this one is device-permission free.", "recommended_fix": "snplclose: if tp->t_sc == NULL (discipline installed via TIOCSETD without SNPSTTY attach), skip snp_down and just run ttylclose under tp->t_token.", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff applied to guest /usr/src, kernel rebuilt (make nativekernel RC=0) and installed (#1 Tue Sep 22 18:38:10 UTC 2026), snp.ko loaded; exact same PoC run as unprivileged maxx: 9 line disciplines found, snoop-disc pty slave closed, no panic, exit=0, guest up. Baseline panic vs patched survive both captured (panic.txt / run.2.log).", "fix_evidence": "run.2.log (patched run output); panic.txt (baseline); fix.diff; build.log" } |