# 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:

```c
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).
