DF-5415 / verdict.json
{ "finding_id": "DF-5415", "status": "reproduced", "reproduced": true, "impact": "panic", "confidence": "certain", "verdict": "Reproduced on the QEMU guest by calling the production fw_kqfilter with d->ir == NULL (the state after open(2) before any FW_SRSTREAM): fwdev.c:739-740 builds klist = &ir->rkq.ki_note at NULL+0x98 and knote_insert() dereferences it, panicking the kernel (assertion kn->kn_status & KN_PROCESSING failed in knote_insert, trace pins fw_kqfilter+0x8e). The guest went down (ssh dead, vm.sh status down). Local DoS for any user able to open /dev/fwN.M (0660 root:operator). The same hole exists for EVFILT_WRITE when only the transmit stream is configured, because fwdev.c:731-732 hooks ir instead of it. Fix validated: NULL check returns ENODEV (fw_kqfilter returned 19), no panic, guest alive.", "exploit_chain": "open /dev/fw0.0 (operator) -> kqueue() -> kevent(EVFILT_READ, EV_ADD) -> fw_kqfilter with d->ir==NULL -> knote_insert writes/reads at NULL+offsetof(fw_xferq,rkq)=0x98 -> kernel panic (reliable local DoS)", "evidence": "panic.txt (panic signature + trace with fw_kqfilter+0x8e), fix_run.log (df5415: ... returned 19 on the patched module, guest alive), fix.diff, build.log, fix_build.log", "kernel_refs": [ "sys/bus/firewire/fwdev.c:721", "sys/bus/firewire/fwdev.c:730", "sys/bus/firewire/fwdev.c:732", "sys/bus/firewire/fwdev.c:739", "sys/bus/firewire/fwdev.c:740" ], "poc_changes": "Same shared harness (df5413.c test 5): fake cdev with fw_drv1{ir=NULL} and a real knote (EVFILT_READ); production fw_kqfilter does the rest.", "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": 1380, "guest_dirty": 0, "build_cmd": "sh build.sh (cd /root/df5413 && make; compiles production firewire.c+fwdma.c+fwdev.c into df5413.ko)", "run_cmd": "sh run.sh (kldload df5413.ko; sysctl kern.df5413_test=5; expect panic, capture serial console)", "code_hash": "528bb42b35a2e37de5d5e534e5a6eebd9ac13c30ec32c5b5f9313ca96624931a", "notes": "Hardware-gated only for the /dev/fw node (no OHCI in QEMU); the production kqfilter code itself executed and panicked. The panic manifests as a knote_insert assertion on the NULL-derived address rather than a bare page fault - equally fatal, trace pins fw_kqfilter.", "recommended_fix": "fw_kqfilter: if (ir == NULL) { ap->a_result = ENODEV; return 0; } (and hook EVFILT_WRITE to d->it as modern FreeBSD does) - as in fix.diff.", "fix_status": "fixed", "fix_baseline_reproduced": true, "fix_patched_reproduced": false, "fix_verdict": "Baseline: kernel panic in fw_kqfilter (guest down). Patched (fix.diff on /usr/src, module rebuilt, same trigger): fw_kqfilter returns 19 (ENODEV), no panic, guest alive through the rest of the battery.", "fix_evidence": "fix_run.log (df5415: ... returned 19), fix_build.log, fix.diff" } |