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

hci_event_inquiry_result/rssi_result: unbounded loops guarded only by KKASSERT -> remote kernel panic on short data

Summary

hci_event_inquiry_result(:447-469) + hci_event_rssi_result(:484-506): trust attacker ep.num_responses(uint8 0-255). Only check KKASSERT(pkthdr.len>=sizeof(ep)=1)(:447/:484). while(ep.num_responses--) loop per iter KKASSERT(pkthdr.len>=sizeof(ir)=15)(:455) / KKASSERT(pkthdr.len>=sizeof(rr)=14)(:492). Controller sends num_responses>N records -> KKASSERT fails -> panic INVARIANTS(default X86_64_GENERIC) / m_copydata NULL-deref non-INVARIANTS. hci_event_hdr_t.length NEVER consulted. Packed structs(hci.h:1862/2092) attacker computes exact short-data. Netbt twin of DF-0542(ng7). Remote unauth BT DoS. Fix: validate num_responses*sizeof(ir)<=remaining upfront, replace KKASSERT with real bounds check.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0559 Β· 8 files
FileTypeDescriptionSize
fix.diff suggested-fix upfront num_responses*sizeof(ir/rr) bound + remove KKASSERT reliance 1.2 KB view raw
build.sh build-script build netbt.ko to validate the fix compiles 439 B view raw
run.sh run-script documents HW-gated trigger (no BT radio on guest) 551 B view raw
VERDICT.md verdict full source trace + why-not-reproducible + fix 3.0 KB ↓ raw
env.txt environment uname, config, netbt module/HW reachability 1.8 KB view raw
fix_build.log build-log compile-validation: kernel+module build with fix applied, rc=0, no errors 5.3 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
VERDICT.md verdict full source trace + why-not-reproducible + fix
↓ download raw

DF-0559 β€” hci_event_inquiry_result / rssi_result unbounded loops

Verdict

NOT TESTABLE at runtime (no Bluetooth hardware) β€” bug CONFIRMED at source (certain). Fix authored in fix.diff; compiled cleanly as part of a combined nativekernel build (netbt.ko) carrying all four verified findings' fixes.

Mechanism (source trace, every hop cited)

Two sibling handlers, both reached from hci_event() (sys/netbt/hci_event.c) at :189-190 (HCI_EVENT_INQUIRY_RESULT) and :193-194 (HCI_EVENT_RSSI_RESULT).

hci_event_inquiry_result() (sys/netbt/hci_event.c:440-470): - KKASSERT(m->m_pkthdr.len >= sizeof(ep)) (:447) β€” only the 1-byte hci_inquiry_result_ep header. Reads ep.num_responses (uint8_t, 0-255, attacker-controlled) (:448-449). - while(ep.num_responses--) (:454) β€” per iteration the only guard is KKASSERT(m->m_pkthdr.len >= sizeof(ir)) (:455) where sizeof(ir) = 15. A KKASSERT is an INVARIANTS-only trap, NOT a runtime bounds check: it panics instead of recovering. Each iteration consumes 15 bytes (m_copydata+m_adj, :456-457).

hci_event_rssi_result() (sys/netbt/hci_event.c:477-507): - Identical shape: KKASSERT(... sizeof(ep)) (:484), reads ep.num_responses (:485), while(ep.num_responses--) (:491) with KKASSERT(m->m_pkthdr.len >= sizeof(rr)) (:492) where sizeof(rr) = 14.

A controller (or injected HCI event) sending num_responses = N but fewer than N*15 (resp. N*14) packed records makes the loop's KKASSERT trip on the 2nd+ iteration when the chain runs out β†’ panic (INVARIANTS ON in X86_64_GENERIC, the production default). On a non-INVARIANTS build, m_copydata on an exhausted chain derefs NULL β†’ panic. Either way it is a remote unauthenticated Bluetooth DoS. hci_event_hdr_t.length (:168) is never consulted.

INVARIANTS being ON means the per-iter KKASSERT is compiled in β€” the reviewer's claim that this manifests as a panic on the default kernel is correct (note: nm ... | grep KASSERT == 0 is a known false negative because KKASSERT/KASSERT expand to inline panic(), not named symbols).

Why not reproduced live (the realistic constraint)

Same as DF-0558: the QEMU/KVM audit guest has no Bluetooth controller. netbt is shipped only as netbt.ko (not in the kernel, not loaded) and no struct hci_unit is ever created, so hci_event()/hci_input() are unreachable. The bug is a genuine latent/net-radio path. The netbt-twin finding DF-0542 (netgraph7 BT) is the same defect in the older stack.

Fix (fix.diff)

For each handler: replace the per-iteration INVARIANTS-only KKASSERT with an explicit upfront bounds check β€” ep.num_responses * sizeof(ir/rr) against the remaining m->m_pkthdr.len, log + return on a malformed event β€” and drop the now-redundant per-iter KKASSERT. Minimal, targeted, recovers gracefully instead of panicking.

PoC changes

findings/poc/DF-0559/ was empty on arrival. This runner authored fix.diff, build.sh, run.sh, README.md, VERDICT.md, manifest.json, env.txt.

Fix verification

not_testable

compile validated rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

Source-confirmed real, no BT HW. hci_event_inquiry_result/rssi_result unbounded loops.