RFCOMM_CHANNEL() mask 0x2f is missing bit 4: inbound server channels 16..30 remap onto 0..14 β incoming connections match the WRONG listening service and channel 16 is permanently unreachable
Summary
A 6-bit DLCI yields a 5-bit channel so the mask must be 0x1f (the inverse MKDLCI correctly uses it): with 0x2f, channels >=16 wrap - PN for channel 17 matched the CHANNEL-1 listener and the accepted DLC was stamped bt_channel=1 (cross-service connection/data mis-attribution on one multiplexer: a trust-boundary crossing - serial-port client connected to the audio service socket); channel 16 maps to 0 and is unreachable. RFCOMM_CHANNEL_MAX=30 so 16..30 are legal listener configurations. one-character mask fix validated (correct listener + bt_channel=17).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5762 Β· 13 files| File | Type | Description | Size | |
|---|---|---|---|---|
| harness.c | β | 16.4 KB | view raw | |
| l2cap_stub.c | β | 3.3 KB | view raw | |
| Makefile | β | 511 B | β download | |
| build.sh | β | 99 B | view raw | |
| run.sh | β | 152 B | view raw | |
| setup.log | β | 393 B | view raw | |
| build.log | β | 4.5 KB | view raw | |
| run.log | β | 8.1 KB | view raw | |
| run.fix.log | β | 60.2 KB | view raw | |
| fix.diff | β | 433 B | view raw | |
| env.txt | β | 312 B | view raw | |
| VERDICT.md | β | 3.0 KB | β raw | |
| verdict.json | β | 4.0 KB | view raw |
DF-5762 VERDICT
Status: reproduced (rig, production code verbatim; deterministic) Impact: dos / cross-service mis-attribution β inbound RFCOMM connections for server channels 17..30 are matched to the WRONG listening socket (channel N&0x2f) and channel 16 is permanently unreachable.
Root cause
sys/netbt/rfcomm.h:217:
#define RFCOMM_CHANNEL(dlci) (((dlci) >> 1) & 0x2f) β 0x2f (0b101111)
lacks bit 4, so 5-bit channel values β₯ 16 wrap: 16&0x2f=0,
17&0x2f=1 β¦ 30&0x2f=14. The inverse macro RFCOMM_MKDLCI
(rfcomm.h:224) correctly uses & 0x1f, so only inbound extraction is
broken. RFCOMM_CHANNEL_MAX is 30 (rfcomm.h:84), i.e. channels 16..30
are fully legal β rfcomm_listen() accepts them (rfcomm_upper.c:320-323)
and local rfcomm_connect() builds correct DLCIs for them; only the
incoming path is broken.
Sinks: rfcomm_dlc_newconn() (sys/netbt/rfcomm_dlc.c:88
chan = RFCOMM_CHANNEL(dlci), matching at :100/:107, stamping at
:133 new->rd_laddr.bt_channel = chan).
Reproduced behaviour (run.log)
Same rig as DF-5760 (verbatim production RFCOMM sources + stub L2CAP):
- PN command, DLCI 34 (channel 17, correct initiator direction):
MASK-CHECK: DLCI 34 (channel 17) planted, rd_laddr.bt_channel = 1and the newconn callback tag shows the channel-1 listener matched ("listener upper 0x1"). In production the channel-17 client would be connected to the channel-1 server socket, with data flowing to the wrong service. - PN command, DLCI 33 (channel 16): DM β
16 & 0x2f = 0matches no listener ("channel 16 NOT planted"), channel 16 is unreachable. - The DF-5760 sweep lines show every channel β₯ 17 matching a shifted-down listener (dlci 0x3d = ch30 β "listener upper 0xe").
Fix validation (run.fix.log)
fix.diff: 0x2f β 0x1f in rfcomm.h, applied in the guest /usr/src,
rig rebuilt from the patched verbatim sources:
MASK-BUG: RFCOMM_CHANNEL(33)=16 ... (35)=17 ... (61)=30(correct extraction).newconn #2 (listener upper 0x11)β the channel-17 listener now matches;MASK-CHECK: ... rd_laddr.bt_channel = 17.- Channel-16 DM gone (not re-tested standalone β channel 16 poison is direction-rejected by the DF-5760 fix in the same patched build; the mask arithmetic itself is printed and correct).
Threat
Remote peer of an established RFCOMM session connecting to services listening on channels 16..30: data mis-delivery between unrelated local services (e.g. audio service socket receiving the serial-port service's connection β a trust-boundary crossing on one multiplexer) and total unreachability of channel 16. No memory corruption. Severity Low.
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.
Fix verification
fixedOne-line mask fix (0x2f -> 0x1f in sys/netbt/rfcomm.h) applied to the guest's /usr/src copy, rig rebuilt from the patched verbatim sources: RFCOMM_CHANNEL(33)=16 / (35)=17 / (61)=30 (printed), the channel-17 PN now matches the channel-17 listener ('newconn #2 (listener upper 0x11)') and the DLC is stamped rd_laddr.bt_channel = 17. Guest alive.
run.fix.log: 'MASK-BUG: RFCOMM_CHANNEL(33)=16 (16 & 0x2f), RFCOMM_CHANNEL(35)=17 ...' (post-fix values), '[upper] newconn #2 (listener upper 0x11)', 'MASK-CHECK: DLCI 34 (channel 17) planted, rd_laddr.bt_channel = 17 (17 == correct match)'.
Confirmed kernel references
Detail
Exploit chain
Remote peer of an established RFCOMM session connects to server channel N in 17..30 -> rfcomm_dlc_newconn matches the listener on channel (N & 0x2f) -> the wrong server socket accepts the connection and receives the data (cross-service trust-boundary crossing on one multiplexer). Channel 16 services are unreachable. No memory corruption.
Evidence (decisive lines)
run.log: 'MASK-CHECK: DLCI 34 (channel 17) planted, rd_laddr.bt_channel = 1' + the matching 'newconn #N (listener upper 0x1)' tag; 'channel 16 NOT planted' (DM, chan 0); 'MASK-BUG: RFCOMM_CHANNEL(33)=0 (16 & 0x2f), RFCOMM_CHANNEL(35)=1 (17 & 0x2f), RFCOMM_CHANNEL(61)=14 (30 & 0x2f)'. run.fix.log: 'MASK-BUG: RFCOMM_CHANNEL(33)=16 ... (35)=17 ... (61)=30', 'newconn #2 (listener upper 0x11)' (the correct channel-17 listener), 'MASK-CHECK: ... rd_laddr.bt_channel = 17'.
PoC changes
Found BY the DF-5760 rig: the channel sweep planted ch17..30 against shifted listeners (dlci 0x23/ch17 -> 'listener upper 0x1', ..., dlci 0x3d/ch30 -> 'listener upper 0xe') and ch16 drew a DM; a dedicated MASK-CHECK PN (correct-direction DLCI 34) was added to make the mis-attribution explicit. Shares the DF-5760 rig files verbatim (see DF-5760/ for harness.c and stubs).
Verified recommended fix
Change the RFCOMM_CHANNEL mask from 0x2f to 0x1f (one line, see fix.diff).
Verdict
Reproduced with the DF-5760 rig (verbatim production RFCOMM sources): RFCOMM_CHANNEL()'s 0x2f mask lacks bit 4, so inbound DLCIs for server channels 16..30 are remapped (16->0, 17->1 ... 30->14). An incoming PN/SABM for channel 17 (DLCI 34/35) matches and is served by the CHANNEL-1 listener and the accepted DLC is stamped rd_laddr.bt_channel = 1 ('MASK-CHECK: DLCI 34 (channel 17) planted, rd_laddr.bt_channel = 1' in run.log) - in production this mis-delivers one local service's connections/data to another service's socket on the same multiplexer; channel 16 (DLCI 32/33 -> chan 0) can never match a listener and is permanently unreachable (DM). Local listeners/connections use the correct MKDLCI (0x1f) - only the inbound extraction is broken. RFCOMM_CHANNEL_MAX is 30, so channels 16..30 are fully legal configurations.
No comments yet.