Signed tx_cred overflow and OOB credit byte read in UIH reception
Summary
tx_cred int16_t(:296) incremented by attacker byte with NO upper bound. ~130 credit-grant UIH frames overflow int16_t. Also: zero-length UIH with PF set reads *mtod stale mbuf byte as credit(:2416) without payload-length check.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-0282 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | source trace: int16_t tx_cred overflow + stale *mtod credit read | 3.5 KB | β raw |
| README.md | readme | claim, runtime status, reproduce (needs BT session), fix | 1.2 KB | β raw |
| fix.diff | suggested-fix | payload guard + tx_cred clamp to RFCOMM_MAX_CREDITS | 1.2 KB | view raw |
| build.sh | build-script | validates fix.diff applies cleanly | 478 B | view raw |
| run.sh | run-script | N/A on this guest | 343 B | view raw |
| fix_build.log | build-log | ng_btsocket.ko module build with fix, rc=0 | 472 B | view raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-0282 β Signed tx_cred overflow + OOB credit byte read in UIH reception
Claim
ng_btsocket_rfcomm_receive_uih() (ng_btsocket_rfcomm.c:2409-2417):
- tx_cred is int16_t (ng_btsocket_rfcomm.h:296); pcb->tx_cred +=
*mtod(m0, u_int8_t *) (line 2416) has no upper bound β ~130 credit UIH frames
overflow int16_t.
- A zero-length UIH with PF set reads *mtod(m0, u_int8_t *) (lines 2413/2416)
with no m_pkthdr.len >= 1 check β stale mbuf byte used as credit.
Runtime status
NOT runtime-testable β the ng_btsocket RFCOMM module is not present on this
guest (/boot/kernel/ng_bt* absent) and there is no Bluetooth hardware to carry
an RFCOMM session. Both defects are definitively confirmed by source trace
(VERDICT.md).
Reproduce (requires Bluetooth stack + RFCOMM session)
Establish an L2CAP RFCOMM session, then (a) send ~130 UIH frames with PF set and
max credit byte to overflow tx_cred, or (b) send a zero-length UIH with PF set
to read a stale credit byte. Not exercisable on this guest.
Fix
fix.diff adds a m_pkthdr.len < 1 guard before reading the credit byte and
clamps tx_cred to RFCOMM_MAX_CREDITS (40). Applies + compiles (ng_btsocket
module).
DF-0282 β VERDICT
Verdict: NOT RUNTIME-TESTABLE on this guest (no Bluetooth RFCOMM socket module / no BT hardware) β source trace DEFINITIVELY CONFIRMS the bug is real.
The claim
Two defects in sys/netgraph7/bluetooth/socket/ng_btsocket_rfcomm.c,
ng_btsocket_rfcomm_receive_uih():
(1) Signed tx_cred overflow (CWE-190)
tx_cred is declared int16_t
(sys/netgraph7/bluetooth/include/ng_btsocket_rfcomm.h:296). In the UIH receive
handler, when a credit-based flow-control DLC has the PF (poll/final) bit set,
the first payload byte is consumed as a credit increment:
2409: if ((pcb->flags & NG_BTSOCKET_RFCOMM_DLC_CFC) && pf) {
2413: __func__, *mtod(m0, u_int8_t *), dlci, ...);
2416: pcb->tx_cred += *mtod(m0, u_int8_t *); /* no upper bound */
2417: m_adj(m0, 1);
*mtod(m0, u_int8_t *) is a full uint8_t (0..255). tx_cred is int16_t
(range -32768..32767). There is no saturation/clamp. Each credit-granting UIH
frame adds up to 255; after ~130 such frames tx_cred wraps past INT16_MAX
into the negative range (signed integer overflow, undefined behaviour; in
practice a negative tx_cred collapses the DLC's transmit window, a logic /
availability defect). RFCOMM_MAX_CREDITS is 40 (ng_btsocket_rfcomm.h:49),
yet nothing bounds tx_cred to it on the receive side.
(2) OOB / stale-byte credit read on zero-length UIH (line 2413/2416)
The credit byte is read with *mtod(m0, u_int8_t *) without first checking
that m0 actually contains a payload byte. A zero-length UIH frame with the PF
bit set reaches line 2413/2416 with m0->m_pkthdr.len == 0; *mtod() then
dereferences the mbuf's data pointer, reading whatever stale byte happens to sit
there (OOB / uninitialized read used as a credit value).
Why not runtime-tested here
The RFCOMM receive path (ng_btsocket_rfcomm_receive_uih) runs inside the
ng_btsocket netgraph7 module on the reception side of an established L2CAP
RFCOMM session. This requires:
- the ng_btsocket (RFCOMM) module loaded β not present on this guest
(/boot/kernel/ng_bt* does not exist; only netbt.ko), and
- a live Bluetooth transport (HCI + L2CAP session) β no Bluetooth hardware.
The defects are therefore not runtime-testable on this guest, but both are
definitively confirmed by source trace: int16_t tx_cred with an unbounded
+= uint8_t (overflow), and *mtod with no m_pkthdr.len >= 1 guard (stale
read).
Realistic impact ceiling
- (1) Signed-overflow of
tx_credfrom ~130 credit UIH frames β transmit-window logic corruption / availability defect on the DLC (a remote peer on an established RFCOMM session can drive it; needs an active BT session). - (2) Stale-byte credit from a zero-length UIH+PF β small OOB / uninitialized read feeding the credit math. Neither is a memory-corruption write primitive; the ceiling is a logic/flow- control defect and a minor info-influence, both behind an active RFCOMM session.
Fix
findings/poc/DF-0282/fix.diff does two things in
ng_btsocket_rfcomm_receive_uih:
1. Adds if (m0->m_pkthdr.len < 1) goto drop1; before consuming the credit byte
(closes the stale-byte read).
2. Captures the credit into a local u_int8_t credit once and clamps the
accumulation: if (pcb->tx_cred + credit > RFCOMM_MAX_CREDITS) tx_cred =
RFCOMM_MAX_CREDITS; else tx_cred += credit; (closes the signed overflow).
Verified git apply --check clean and compiles into the ng_btsocket module.
fix_status: not_testable (diff applies + compiles; runtime not exercisable
without BT hardware/module).
Fix verification
not_testablecompile validated
module/kernel build rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed. RFCOMM tx_cred int16 overflow + zero-length UIH credit *mtod stale read. No BT HW/module.
No comments yet.