DF-5760 / verdict.json
{ "finding_id": "DF-5760", "status": "reproduced", "reproduced": true, "impact": "dos", "confidence": "certain", "verdict": "Reproduced deterministically with a KLD rig compiling the verbatim production rfcomm_session.c/rfcomm_dlc.c/rfcomm_upper.c against a stubbed L2CAP layer: one PN command with a responder-direction DLCI (7 = channel 3, our direction on a responder session) is accepted by the production recv_mcc_pn -> rfcomm_dlc_newconn path (no direction check, channel-only matching), fabricating a DLC+socket child in the local stacks own DLCI space; every subsequent local rfcomm_connect() to that channel returns EBUSY (rfcomm_upper.c:181-182) until the session dies. Sweeping 30 channels locks the local RFCOMM client out of every server channel (28/29 in run.log; the 29th is blocked by the DF-5762 mask bug). recv_sabm() has the exact missing check (rfcomm_session.c:738-742). Guest stays up: pure validation/logic bug, remote-peer-triggerable DoS plus rogue half-open DLC/socket allocation.", "exploit_chain": "Bluetooth-adjacent peer with an established RFCOMM session to the victim service: (1) send PN command with DLCI = MKDLCI(local-direction, ch) for each channel 1..30 -> each creates a rogue DLC via the listening sockets newconn (socket allocation) stuck in WAIT_CONNECT; (2) any local application connect() to those channels now gets EBUSY forever; (3) rogue DLCs linger until session teardown. No memory corruption; ceiling is permanent local-outbound lockout + resource poisoning.", "evidence": "run.log: POISON-CONFIRMED: peer-planted DLCI 7 exists on session (state 2), LOCAL-CONNECT: rfcomm_connect(ch 3) -> 16 (EBUSY = 16) <== locked out by peer, POISON-SWEEP: 28/29 poisoned channels refuse local connect with EBUSY, RESULT: PEER CAN LOCK THE LOCAL RFCOMM CLIENT OUT OF ALL CHANNELS; run.fix.log: poison rejected (DLCI 7 state -1), connect -> 0 accepted, newconn calls: 2; setup.log md5s prove verbatim production sources.", "kernel_refs": [ "sys/netbt/rfcomm_dlc.c:72", "sys/netbt/rfcomm_dlc.c:88", "sys/netbt/rfcomm_dlc.c:92-111", "sys/netbt/rfcomm_dlc.c:128-140", "sys/netbt/rfcomm_session.c:1322-1331", "sys/netbt/rfcomm_session.c:738-742", "sys/netbt/rfcomm_upper.c:180-182" ], "poc_changes": "Adapted the DF-5733 rig (l2cap_stub + inject helpers) to a listener scenario: stub l2cap_sockaddr returns BDADDR_ANY so 30 listeners share one listening session (first iterations fixed 0x11 bdaddr exhausted the stub channel table and crashed in harness code - fixed); listener newconn callback returns fresh rfcomm_attachd child DLCs (sonewconn stand-in); added per-channel PN sweep, fresh probe DLC per channel, listener-identity tags (upper = channel number), and a MASK-CHECK probe shared with DF-5762.", "attempts": 4, "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": 2700, "guest_dirty": 0, "build_cmd": "cd /root/df5760 && sh build.sh (copies verbatim /usr/src/sys/netbt sources, KLD make)", "run_cmd": "kldload /root/df5760/rfcomm_pn_harness.ko && sysctl hw.rfcomm_pn_fire=1 (reboot required between runs: MOD_UNLOAD is EBUSY)", "code_hash": "137c459cd205977dfe37c2d74b48fe42bfc8a242f0989ef27c9ae28946626894", "notes": "Baseline + fix-validated in the same session with byte-identical injected frames. The DF-5762 mask bug surfaced inside this rigs sweep (ch16 DM / shifted listener matches) and is filed separately. Rig-internal stub crash on iteration 1 was a harness bug (documented in VERDICT.md), not a production finding.", "recommended_fix": "Add the direction-bit validation to rfcomm_session_recv_mcc_pn()s PN-command path, mirroring rfcomm_session_recv_sabm() (see fix.diff).", "fix_status": "fixed", "fix_baseline_reproduced": true, "fix_patched_reproduced": false, "fix_verdict": "fix.diff (direction check in recv_mcc_pn, DM on violation) applied to the guests /usr/src/sys/netbt copy; rig rebuilt from the patched verbatim sources; same harness and identical frames: PN(DLCI 7) answered with DM, no DLC created (newconn calls: 2), local rfcomm_connect(ch 3) -> 0 (accepted, previously EBUSY), sweep poison fully rejected, guest alive.", "fix_evidence": "run.fix.log lines: DUP-CHANNEL: ... peer-planted DLCI 7 (state -1), LOCAL-CONNECT: rfcomm_connect(ch 3) -> 0 (EBUSY = 16) (unexpected), POISON-SWEEP: 1/29 (the 1 is ch4s own baseline DLC); uptime captured in transcript; same-run MASK-CHECK also validates the DF-5762 mask fix." } |