ACL reassembly want is uint16_t: overshoot wraps -> L2CAP RX stall + unbounded memory growth
Summary
want declared uint16_t(:421). Computed want=letoh16(want)+sizeof(l2cap_hdr_t)-got(:509) in mixed int/size_t then truncated 16 bits. When accumulated got exceeds claimed L2CAP frame size(l2cap_len+4) β happens when HCI ACL START overshoots L2CAP boundary or fragments overshoot β subtraction goes negative wraps to large uint16_t. if(want>0)return(:511) taken forever after: (1) completed frame stuck in hl_rxp never delivered L2CAP traffic stalled DoS; (2) every subsequent FRAGMENT m_cat onto hl_rxp no upper bound(:495-498) kernel memory grows unbounded M_BLUETOOTH. Trigger: malicious/buggy USB BT dongle or controller firmware defect inducible by remote peer. Fix: declare int want(signed 32-bit) gate on signed value, trim overshoot via m_adj reprocess trailing bytes as fresh START, enforce hard cap on hl_rxp growth.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-0566 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| fix.diff | suggested-fix | use int want_total for arithmetic, preserve 2-byte read | 466 B | view raw |
| env.txt | environment | uname (no BT modules loaded) | 297 B | view raw |
| VERDICT.md | verdict | source-trace confirmation + unreachability note | 3.4 KB | β raw |
| README.md | readme | bug description and reachability | 2.5 KB | β 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-0566 β Bluetooth ACL reassembly uint16_t want overflow
Bug
hci_acl_recv (sys/netbt/hci_link.c:417) accumulates ACL fragments
until a complete L2CAP frame is ready. The completion test at line 509
is:
uint16_t want; /* line 421 -- 16-bit type */
...
m_copydata(m, 0, sizeof(want), &want);
want = letoh16(want) + sizeof(l2cap_hdr_t) - got; /* line 509 */
if (want > 0) /* line 511 */
return;
...
if (want == 0) { /* line 516 */
l2cap_recv_frame(m, link);
return;
}
The right-hand side is computed in size_t (because of
sizeof(l2cap_hdr_t)), then truncated to uint16_t on assignment.
When an HCI ACL START frame or accumulated fragments overshoot the
claimed L2CAP length (got > letoh16(want) + 4), the subtraction
underflows:
- Arithmetic in size_t: huge 64-bit value
- Truncated to uint16_t: 16-bit pattern (e.g. 0xFF9C for a -100 overshoot)
want > 0is now true βreturnwithout delivering or freeing the frame
Consequences (DoS, no memory corruption since want is just a local
variable):
1. The half-completed frame is stuck in link->hl_rxp indefinitely;
no L2CAP traffic for that handle is ever delivered.
2. Every subsequent FRAGMENT is m_cat'd onto hl_rxp (line 496)
without bound, growing it indefinitely β unbounded kernel memory
consumption.
The opposite-direction bug (got MUCH larger than claimed L2CAP length due to malicious HCI input) is the more interesting primitive but is gated behind actual Bluetooth hardware.
Reachability on this guest
The trigger path requires an HCI ACL packet to reach hci_acl_recv.
That function is only called from hci_unit.c:382 (the HCI unit's RX
queue, drained by the Bluetooth hardware driver). There is no
virtual Bluetooth device on DragonFlyBSD and no in-kernel path
from userspace to hci_acl_recv β HCI sockets (BTPROTO_HCI) bind to
an existing unit and exchange control commands, they do not inject RX
packets.
The guest has no Bluetooth hardware (ng_ubt / bt3c / etc. not
loaded; no USB BT dongle). Therefore this bug cannot be reproduced
at runtime on this guest. The bug is real and traced line-by-line
into the source (see VERDICT.md); it is a latent defect that would
manifest on any DFly system with a Bluetooth HCI device under
adversarial RF/peer input.
Fix
Use a wider signed type for the arithmetic (the L2CAP length field
read stays 16-bit, but the comparison value is computed in int).
See fix.diff. The fix preserves the 2-byte m_copydata and fixes the
truncation.
DF-0566 β Verdict: NOT TESTABLE (no Bluetooth hardware)
Verdict
CONFIRMED by source trace; NOT TESTABLE at runtime on this guest
(no Bluetooth HCI device or virtual BT path; the only caller of
hci_acl_recv is the HCI unit RX queue fed by a BT driver).
Bug confirmation (source-only)
- sys/netbt/hci_link.c:421 β
uint16_t want;(16-bit type) - sys/netbt/hci_link.c:508 β
m_copydata(m, 0, sizeof(want), &want);reads 2 bytes (the L2CAPlengthfield). Correct. - sys/netbt/hci_link.c:509 β `want = letoh16(want) + sizeof(l2cap_hdr_t)
- got;
arithmetic in size_t (becausesizeof` returns size_t), truncated to uint16_t on assignment. - sys/netbt/l2cap.h:219-220 β
l2cap_hdr_tis{ uint16_t length; uint16_t dcid; }(4 bytes packed). Sosizeof(l2cap_hdr_t) == 4. - sys/netbt/hci_link.c:511 β
if (want > 0) return;takes the "incomplete" branch forever oncewanthas wrapped, because the truncated value is non-zero. - sys/netbt/hci_link.c:516 β
if (want == 0)deliver branch never taken. - sys/netbt/hci_link.c:495-498 β fragment branch: `got = m->m_pkthdr.len
- link->hl_rxp->m_pkthdr.len; m_cat(...); m->m_pkthdr.len = got;` β subsequent fragments pile onto hl_rxp without bound.
The reviewer's analysis is correct. The truncation math is real.
Trigger unreachability on this guest
hci_acl_recvis called ONLY fromsys/netbt/hci_unit.c:382which dequeues fromunit->hci_aclrxq.- The RX queue is fed by Bluetooth HCI drivers (e.g.
ng_ubt,bt3c). None are loaded on this guest and no virtual BT device exists in DFly. - The BTPROTO_HCI socket family (
sys/netbt/hci_socket.c) binds to an existing unit; it does NOT inject RX packets. - Confirmed by
kldstat: only ehci/xhci USB host controllers, no BT modules. No BT hardware in QEMU config.
Therefore: this is a latent bug. To exercise it on a DFly system
requires either:
- A physical USB BT dongle plugged in, with a malicious peer that
sends ACL packets overshooting the L2CAP length, OR
- A kernel-module test harness that allocates a struct hci_unit,
synthesizes ACL mbufs, and calls hci_acl_recv directly.
The latter would be a developer-only characterization (the
kldload-based test harness is explicitly OUT OF SCOPE for
escalation per the bright-line rule, but is mentioned here as the
concrete next step for a maintainer wanting to exercise the path).
Impact ceiling
- Per-link DoS: L2CAP traffic stalls; hl_rxp grows unbounded.
- No memory corruption primitive (the truncated
wantis a local; the only effect is wrong control flow + unbounded m_cat). - Affects only systems with active Bluetooth HCI (small subset of DFly deployments).
Fix validation
Not testable at runtime (no BT hardware). Validated by:
1. Source line-by-line trace (above).
2. fix.diff applies cleanly with patch -p1 --dry-run against
sys/netbt/hci_link.c (single hunk, line 509).
Kernel references
- sys/netbt/hci_link.c:421 β uint16_t want declaration
- sys/netbt/hci_link.c:508 β m_copydata read (correct)
- sys/netbt/hci_link.c:509 β truncating arithmetic (BUG)
- sys/netbt/hci_link.c:511 β broken
want > 0return - sys/netbt/hci_link.c:516 β unreachable
want == 0deliver - sys/netbt/hci_link.c:495-498 β fragment pile-on
- sys/netbt/l2cap.h:219-220 β l2cap_hdr_t is 4 bytes
- sys/netbt/hci_unit.c:382 β sole caller, fed by BT driver RX queue
Fix verification
not_testablecompile validated
see evidence pack
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed. BT ACL reassembly want uint16_t overshoot wraps -> stuck forever + m_cat pile-on. No BT HW.
No comments yet.