# DF-3790 — verdict

**INCONCLUSIVE** | reproduced=0 | impact=none | confidence=certain

INCONCLUSIVE at runtime (needs the bktr device + VBI interrupts; absent on this guest). Source-certain: the inverted call is unambiguous and the knote lifecycle (kern_event.c:1764-1774, 2084-2097 knote_free cache) confirms the dangling entry and interrupt-context consumer.

## Root cause (citations)
bktr_kqfilter() (sys/dev/video/bktr/bktr_os.c:718-719) inserts the knote
into bktr->vbi_kq.ki_note. When the knote is destroyed (EV_DELETE, kqueue
close, fd close), knote_detach_and_drop() (sys/kern/kern_event.c:1764-1774)
calls f_detach = bktr_filter_detach(), which must REMOVE the knote - but it
calls knote_INSERT() again (bktr_os.c:724-732; every other DF driver's
f_detach calls knote_remove()). SLIST_INSERT_HEAD of an element already on
the list corrupts the list (self-loop when it is head). knote_drop() then
frees the knote, leaving a dangling (possibly self-referential) entry on
vbi_kq.ki_note. The VBI even-field interrupt path KNOTE(&bktr->vbi_kq.ki_note,
0) at bktr_core.c:705 then walks the corrupted list from interrupt context:
deref of freed knote (knote cache memory, reused for unrelated knotes ->
f_event on wrong filterops/hook) and/or infinite self-loop walk holding the
pool token -> hard hang. Root cause is in bktr_os.c (pass-1 marked that file
clean and missed it); the consuming KNOTE() is in this file. Unprivileged:
/dev/vbi0 is 0444.

## Guest reality (why no runtime kernel trigger)

The audit guest is DragonFly 6.5-DEVELOPMENT x86_64 (X86_64_GENERIC). The bktr
driver is NOT compiled into the GENERIC kernel (`sys/conf/files`: `optional
bktr pci`), there is no /boot/modules tree, no /dev/bktr*, /dev/tuner*,
/dev/vbi* nodes, no Brooktree PCI device (QEMU has no Bt848/Bt878 device
model; `pciconf -lv` shows no vendor 109e). Therefore the kernel code path is
unreachable ON THIS GUEST. Verification is source-level: faithful harnesses of
the exact kernel arithmetic (the same methodology as the accepted DF-1216
evidence pack), run on the DragonFly guest with its native cc, plus fix.diff
compile-validation against the guest's /usr/src. All PoC triggers compile
cleanly against the guest's kernel headers (poc_build_and_device_check.log).


## Exploit chain
open /dev/vbi0 (0444) -> kqueue EVFILT_READ ADD on it -> EV_DELETE the note (f_detach re-inserts; knote freed + cached) -> keep /dev/vbi0 open, start PAL continuous capture -> even-field interrupt KNOTE() walks the dangling/self-looped entry -> UAF call or infinite loop with pool token held.

## Decisive evidence
poc_knote_detach.c (compiles on guest vs /usr/src headers; /dev/vbi0 absent). VERDICT.md cites the lifecycle chain.

## Fix validation
fix.diff (in this directory) applies cleanly against the pristine sys/ tree
(`git apply --check`) and compiles as part of the bktr KLD module on the
guest's /usr/src with -Werror together with the seven other pass-2 bktr fixes
(fix_build.log, MAKE_RC=0, bktr.ko + bktr_mem.ko produced). Runtime
patched-behavior validation is not possible on this guest (no device), hence
fix_status=not_testable (compile-validated + logic-reviewed).

## Kernel references
- sys/dev/video/bktr/bktr_os.c:724
- sys/dev/video/bktr/bktr_os.c:731
- sys/dev/video/bktr/bktr_os.c:718
- sys/dev/video/bktr/bktr_core.c:705
- sys/kern/kern_event.c:1764
- sys/kern/kern_event.c:1902

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
