DF-5747 / verdict.json
{ "finding_id": "DF-5747", "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 (md5-verified vs /usr/src/sys/netbt) against a stub L2CAP layer. Production rfcomm_bind() (rfcomm_upper.c:103-109) accepted a re-bind of a live LISTENing DLC: bind #2 in state 8 returned 0 and mutated the listeners advertised channel 3->5 and psm 0x0003->0x1001 in place. NetBSD upstream returns EINVAL for exactly this call (state check in rfcomm_bind_pcb(), still present in rfcomm_upper.c 1.24/2024); DragonFly never took the fix. Pure semantic/state-confusion bug confined to the callers own sockets (rfcomm_listens channel allocator and rfcomm_dlc_newconns best-match both consume rd_laddr.bt_channel); no memory unsafety, no cross-privilege effect - hence Info severity. One-line fix validated on the guest: patched build returns 22/EINVAL for the LISTEN-state bind while the CLOSED-state bind still succeeds and teardown stays clean.", "exploit_chain": "", "evidence": "run.log: [DF-5747] bind #2 (state LISTEN) -> 0 (BUG: live listener mutated; upstream returns EINVAL) and listener now advertises: channel=5 psm=0x1001 state=8; fix_run.log: bind #2 (state LISTEN) -> 22 (EINVAL - fixed) with channel=3 psm=0x0003 preserved; fix_build.log: objdump of patched rfcomm_bind showing cmpw rd_state/mov $0x16 (EINVAL); setup.log: verbatim-source md5s", "kernel_refs": [ "sys/netbt/rfcomm_upper.c:103-109", "sys/netbt/rfcomm_upper.c:357-373", "sys/netbt/rfcomm_dlc.c:92-113" ], "poc_changes": "Harness written fresh on the DF-5733 rig pattern (verbatim netbt sources + l2cap_stub.c + FCS-valid frame injectors were not needed here - only production upper-API calls); stub gained harness_last_channel(); no production source modified for the baseline run.", "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": 8, "guest_dirty": 0, "build_cmd": "cd /root/rfup/DF-5747 && ./build.sh (make -m /usr/src/share/mk SYSDIR=/usr/src/sys)", "run_cmd": "cd /root/rfup/DF-5747 && ./run.sh && dmesg | tail", "code_hash": "0ddb3bdabd9c9816c15f01ae9d4ad295ae9e4845437eab0a0732e7a43b993ef8", "notes": "Fix-validation note: the first patched rebuild without make clean/MAKEOBJDIRPREFIX relinked a stale rfcomm_upper.o from a second objdir and showed unchanged behavior; the clean rebuild (disassembly-verified) is the validated one. Guest left clean via vm.sh reset with-src. netbt is not in X86_64_GENERIC; rig compiles it into the module, which is why a socket-level PoC was not possible on this guest.", "recommended_fix": "Add the upstream NetBSD state check to rfcomm_bind(): reject with EINVAL unless dlc->rd_state == RFCOMM_DLC_CLOSED (see fix.diff).", "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 applied to the verbatim rig copy with patch -p3, clean-rebuilt, reloaded, same trigger: bind #2 (state LISTEN) now returns 22/EINVAL and the listener keeps channel=3/psm=0x0003; bind #1 (CLOSED) still returns 0; detach/teardown clean. Bad behavior gone on patched build.", "fix_evidence": "fix_run.log ([DF-5747] bind #2 (state LISTEN) -> 22 (EINVAL - fixed)); fix_build.log (patch output + relink + rfcomm_bind disassembly with the EINVAL path)" } |