β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-0282

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0282 Β· 8 files
FileTypeDescriptionSize
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
README.md readme claim, runtime status, reproduce (needs BT session), fix
↓ download 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).

VERDICT.md verdict source trace: int16_t tx_cred overflow + stale *mtod credit read
↓ download raw

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_cred from ~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_testable

compile 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.