DF-5748 / verdict.json
{ "finding_id": "DF-5748", "status": "reproduced", "reproduced": true, "impact": "none", "confidence": "certain", "verdict": "Reproduced on the QEMU guest with a KLD rig compiling sys/netbt/rfcomm_session.c, rfcomm_dlc.c, rfcomm_upper.c VERBATIM against a stub L2CAP layer, driving two DLCs to RFCOMM_DLC_OPEN through the production session state machine with injected FCS-valid TS 07.10 frames. After production rfcomm_disconnect() armed the 20 s ack timer (callout_pending=1 callout_active=1), the production rfcomm_dlc_close() - the identical call rfcomm_detach() makes at rfcomm_upper.c:278-279 - left callout_active()==0: callout_stop() clears CALLOUT_ACTIVE unconditionally at entry (kern_timeout.c:869) and drains in-progress callbacks (kern_timeout.c:888-921). Since no callout_reset(&dlc->rd_timeout) site is reachable with rd_state==CLOSED, the callout_active() test at rfcomm_upper.c:293 can only ever see 0, RFCOMM_DLC_DETACH can never be set, and the kfree() branch in rfcomm_dlc_timeout() (rfcomm_dlc.c:203-204) is unreachable dead code - demonstrated live, then full production rfcomm_detach() ran the immediate-kfree path and the session expired cleanly 20 s later with no crash. Not directly exploitable (the unconditional kfree is safe precisely because callout_stop drains), but the guard is documented as the callout-vs-detach lifetime handler and does nothing - the genuine race is DF-0724, and this dead net invites fixing it the wrong way. Info severity (dead code / misleading guard / upstream divergence: NetBSD uses callout_invoking() there).", "exploit_chain": "", "evidence": "run.log: [DF-5748] A timer: pending=1 active=1 (ARMED by rfcomm_disconnect:252) followed by [DF-5748] A after rfcomm_dlc_close(): pending=0 active=0 and [DF-5748] DEAD: callout_active() == 0 after rfcomm_dlc_close(); the RFCOMM_DLC_DETACH branch at rfcomm_upper.c:293 is UNREACHABLE, then rfcomm_detach(B) returned; B freed via immediate kfree (DETACH flag never taken) and === DF-5748 harness done (no crash) ===; fix_run.log: identical clean lifecycle with the dead code removed; setup.log: verbatim-source md5s", "kernel_refs": [ "sys/netbt/rfcomm_upper.c:289-296", "sys/netbt/rfcomm_upper.c:249-253", "sys/netbt/rfcomm_dlc.c:164", "sys/netbt/rfcomm_dlc.c:201-204", "sys/kern/kern_timeout.c:869", "sys/kern/kern_timeout.c:888-921" ], "poc_changes": "Harness written fresh on the DF-5733 rig pattern: verbatim netbt sources + l2cap_stub.c (gained harness_last_channel()) + FCS-valid frame injectors reused; drives two DLCs (DLCI 6/8) so one demonstrates the callout state around rfcomm_dlc_close() while the other runs full production rfcomm_detach(); no production source modified for the baseline run.", "attempts": 1, "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": 26, "guest_dirty": 0, "build_cmd": "cd /root/rfup/DF-5748 && ./build.sh (make -m /usr/src/share/mk SYSDIR=/usr/src/sys)", "run_cmd": "cd /root/rfup/DF-5748 && ./run.sh && dmesg | tail", "code_hash": "9f7519da1a0253726724e7abdff096d60500f6eb66293e2e9b957c57e3eafbb2", "notes": "Self-expiry of the emptied session (20 s ack timer -> rfcomm_session_timeout -> rfcomm_session_free) was slept out inside the trigger to leave no armed callout referencing module text. Guest left clean via vm.sh reset with-src.", "recommended_fix": "Delete the dead callout_active()/RFCOMM_DLC_DETACH machinery: unconditional documented kfree in rfcomm_detach() and drop the unreachable release branch in rfcomm_dlc_timeout() (see fix.diff); fix the real race (DF-0724) separately with proper serialization.", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 (same guest, rig-level rebuild of the verbatim sources)", "fix_verdict": "fix.diff (two hunks) applied to the verbatim rig copies, clean-rebuilt with zero callout_active references remaining in the module, reloaded, same trigger: the full DLC lifecycle runs identically and cleanly - behavior-preserving dead-code removal validated (nothing bad to reproduce by design; baseline_reproduced=1 refers to the demonstrated dead guard, patched_reproduced=0 to the absence of any fault).", "fix_evidence": "fix_build.log (both hunks applied, relink, callout_active grep count 0); fix_run.log (identical lifecycle, === DF-5748 harness done (no crash) ===)" } |