num_compl_pkts: unbounded variable-length loop reads past mbuf end -> remote kernel panic
Summary
num_compl_pkts(:884-924): pulls up sizeof(num_compl_pkts_ep)=1 byte(num_con_handles)(:884) m_adj(:889). Loops for(;num_con_handles>0;num_con_handles--)(:891). num_con_handles attacker-controlled NEVER validated vs remaining mbuf length. Each iter m_copydata(sizeof(h)=2)+m_copydata(sizeof(p)=2)+m_adj = 4 bytes. Body shorter than 4*count -> chain exhausted -> m_copydata KASSERT/NULL-deref panic. Same root cause: ng_hci_process_event never enforces hdr->length. Remote unauth BT. Fix: clamp num_con_handles to m_pkthdr.len/4.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-0543 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | readme | claim, byte-count trace, repro status, fix | 3.0 KB | β raw |
| VERDICT.md | verdict | full narrative: source-confirmed OOB, dead-code blocker, fix | 3.0 KB | β raw |
| fix.diff | suggested-fix | bound num_compl_pkts loop by m_pkthdr.len (4 bytes/entry) | 887 B | view raw |
| build_hci.log | build-log | patched ng_hci.ko module build (both fixes), rc=0 clean | 10.4 KB | view raw |
| build_result.txt | build-log | module builds; kldload fails (ng_bluetooth absent) | 745 B | view raw |
| env.txt | environment | uname, cc, module availability, reachability conclusion | 1.6 KB | view raw |
| hci_event_analysis.sh | trigger-source | source-level byte-layout analysis of a triggering NUM_COMPL_PKTS HCI event | 1.7 KB | 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-0543 β num_compl_pkts: unbounded loop reads past mbuf (netgraph7 HCI)
File: sys/netgraph7/bluetooth/hci/ng_hci_evnt.c
Severity (fileed): High
Class: Out-of-bounds read (mbuf chain over-read) β kernel panic
Module: ng_hci (netgraph7 bluetooth) β NOT compiled, NOT shipped, NOT
loadable on the default X86_64_GENERIC guest. (Same root cause class as
DF-0542: ng_hci_process_event never enforces hdr->length.)
The claim (source-level, CONFIRMED)
num_compl_pkts() (ng_hci_evnt.c:884) pulls up only
sizeof(ng_hci_num_compl_pkts_ep) = 1 byte (num_con_handles) and loops:
for (; ep->num_con_handles > 0; ep->num_con_handles --) { /* :891 */
m_copydata(event, 0, sizeof(h), &h); m_adj(event, sizeof(h)); /* 2 bytes */
m_copydata(event, 0, sizeof(p), &p); m_adj(event, sizeof(p)); /* 2 bytes */
...
}
Each iteration consumes 4 bytes (sizeof(h)=2 + sizeof(p)=2; both are
u_int16_t declared at :882). The controller-supplied num_con_handles
(first body byte) is never validated against the mbuf length β
ng_hci_process_event (:86) logs hdr->length (:100) but does not enforce
it.
A 1-byte event body with num_con_handles = 0xFF (255) demands 1020 bytes but
the chain holds far less. Once m_adj drains the chain, m_copydata() walks
m = m->m_next to NULL and hits KASSERT(m != NULL, "length > size of mbuf
chain") at sys/kern/uipc_mbuf.c:1687 β panic (INVARIANTS/GENERIC);
non-INVARIANTS β NULL m->m_len deref β page-fault panic.
Reproduction status
- Source-level: CONFIRMED (4-byte/iteration math and
m_copydataKASSERT traced). - Live trigger: NOT possible on the default guest β same as DF-0542:
netgraph7 bluetooth is
optional netgraph7_bluetooth, absent fromX86_64_GENERIC, no.koships,kldload ng_hci.kofails ("depends on ng_bluetooth - not available"), and reachingnum_compl_pkts()needs a real HCI NUMBER_OF_COMPLETED_PACKETS event from a BT controller viang_ubt/ng_h4. β dead code / latent here.
Impact (realistic, conditional)
Conditional on netgraph7 bluetooth being compiled in + a BT controller:
remote-unauthenticated-packet β kernel panic (DoS). No info-leak path here
(the parsed h/p are looked up against existing connections and only a
counter is updated β :903-919; the over-read reaches the KASSERT/NULL-deref,
not a copyout). On the shipped default kernel this code is absent β none.
Old netgraph BT?
sys/netgraph/bluetooth/ does not exist in this tree; only netgraph7 carries
this parser. No second copy to fix.
Fix
fix.diff β bound the loop by remaining mbuf length:
for (; ep->num_con_handles > 0 &&
event->m_pkthdr.len >= (sizeof(h) + sizeof(p)); /* 4 bytes/entry */
ep->num_con_handles --) { ... }
git-apply clean; compiles (patched ng_hci.ko build rc=0, build_hci.log).
Build
cd /usr/src/sys/netgraph7/bluetooth/hci && make # -> ng_hci.ko (objdir), rc=0
Logs: build_hci.log, build_result.txt, env.txt.
DF-0543 β VERDICT
Verdict: NOT REPRODUCED at runtime (source-CONFIRMED real OOB-read; the
vulnerable code is dead/opt-in on the default guest).
Impact: none on a default install (latent; conditional on
netgraph7_bluetooth + BT hardware).
Confidence: likely (bug confirmed by source trace; not runtime-observed
because the module is not compiled/shipped/loadable on the default guest).
Mechanism (source-confirmed)
ng_hci_process_event()(ng_hci_evnt.c:86) pulls the 3-byte HCI header, logshdr->length(:100) but does not enforce it, dispatches onhdr->event(:106).NG_HCI_EVENT_NUM_COMPL_PKTSβnum_compl_pkts()(:171,:878).num_compl_pkts()pulls onlysizeof(ng_hci_num_compl_pkts_ep)= 1 byte (num_con_handles) (:884),m_adjs it (:889), then loopsfor (; ep->num_con_handles > 0; ...)(:891) with no length guard.- Each iteration consumes 4 bytes:
m_copydata(sizeof(h)=2)+m_adj(2)(:893-894) andm_copydata(sizeof(p)=2)+m_adj(2)(:898-899).h,pareu_int16_t(:882). - When
num_con_handlesexceeds the chain's data,m_adjdrains the chain to NULL; the nextm_copydata()walksm = m->m_nextto NULL and tripsKASSERT(m != NULL, "%s: length > size of mbuf chain")atsys/kern/uipc_mbuf.c:1687β panic (INVARIANTS/GENERIC); non-INVARIANTS β NULLm->m_lenderef β page-fault panic. No copyout path (parsed values only update an in-kernel connection counter), so this is panic/DoS, not a direct info leak.
Same root cause as DF-0542 (ng_hci_process_event never validates
hdr->length). The bug is real and not a false positive.
Why NOT reproduced at runtime
Identical to DF-0542: netgraph7 bluetooth is optional netgraph7_bluetooth,
absent from X86_64_GENERIC, no .ko ships, standalone ng_hci.ko builds but
kldload fails ("depends on ng_bluetooth - not available"), and reaching
num_compl_pkts() requires a real HCI event from a BT controller. β dead/
unreachable at runtime on this guest AND no userspace harness can exercise it
without building the netgraph7 BT stack (root) + BT hardware β a valid hard
blocker for live reproduction.
Fix-validation (fix.diff)
fix.diff bounds the loop by remaining event->m_pkthdr.len:
for (; ep->num_con_handles > 0 &&
event->m_pkthdr.len >= (sizeof(h) + sizeof(p));
ep->num_con_handles --) { ... }
- git-apply clean; compiles (patched
ng_hci.kobuild rc=0,build_hci.log). fix_status: not_testable (runtime). Validated apply + compile; traced to close the over-read.
PoC changes
Created the evidence pack from scratch (empty on handoff): README.md, this
VERDICT.md, env.txt, build_result.txt, build_hci.log, fix.diff,
manifest.json.
Recommended fix (summary)
In sys/netgraph7/bluetooth/hci/ng_hci_evnt.c, bound num_compl_pkts()'s
loop by the remaining mbuf length (stop when event->m_pkthdr.len <
sizeof(h)+sizeof(p), 4 bytes/entry). (Matches the finding's "clamp
num_con_handles to m_pkthdr.len/4" proposal.)
Fix verification
not_testablenot_testable: compile validated, no runtime trigger.
git apply --check OK + module build rc=0.
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
Source trace + compile validation. No live trigger.
PoC changes
fix.diff + VERDICT.md + manifest.json per finding.
Verified recommended fix
See individual fix.diff per finding.
Verdict
Source-confirmed real but not runtime-reproduced. See individual evidence packs.
No comments yet.