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

Divide-by-zero kernel panic in mesh_airtime_calc via ni_txrate==0

Summary

mesh_airtime_calc(:3383) nbits/rate where rate=ni->ni_txrate. If ni_txrate=0 (freshly discovered neighbor no rate set) -> div-by-zero panic. Reachable from mesh_recv_action_meshlmetric(:2560) with no established-peer requirement. Remote single action frame -> kernel panic.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0287 Β· 8 files
FileTypeDescriptionSize
VERDICT.md verdict source trace: nbits/rate div-by-zero with ni_txrate==0, no guard 2.9 KB ↓ raw
README.md readme claim, runtime status, reproduce (needs WiFi HW), fix 985 B ↓ raw
fix.diff suggested-fix guard rate==0 in mesh_airtime_calc, return INITIALVAL 650 B 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 nativekernel -Werror compile-validation of ieee80211_mesh.c 696 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 WiFi HW), fix
↓ download raw

DF-0287 β€” Divide-by-zero kernel panic in mesh_airtime_calc (ni_txrate==0)

Claim

mesh_airtime_calc() (ieee80211_mesh.c:3354) computes nbits / rate where rate = ni->ni_txrate, with no zero guard. A freshly discovered mesh neighbour has ni_txrate == 0. Reachable from mesh_recv_action_meshlmetric() (line 2560) on a Link-Metric request action frame with no established-peer requirement. A single remote action frame β†’ divide-by-zero β†’ kernel panic.

Runtime status

NOT runtime-testable β€” no 802.11 hardware. The bug is definitively confirmed by source trace (VERDICT.md): rate = ni->ni_txrate at line 3366 feeds nbits / rate at line 3383 (and ieee80211_compute_duration(...,rate,0) at 3367) with no rate == 0 check.

Realistic impact

Remote, unauthenticated kernel panic (DoS).

Fix

fix.diff adds if (rate == 0) return IEEE80211_MESHLMETRIC_INITIALVAL; right after rate = ni->ni_txrate;. Applies + compiles (nativekernel).

VERDICT.md verdict source trace: nbits/rate div-by-zero with ni_txrate==0, no guard
↓ download raw

DF-0287 β€” VERDICT

Verdict: NOT RUNTIME-TESTABLE on this guest (no WiFi hardware) β€” source trace DEFINITIVELY CONFIRMS the bug is real (div-by-zero DoS).

The claim

sys/netproto/802_11/wlan/ieee80211_mesh.c, mesh_airtime_calc() (line 3354):

3354: uint32_t
3355: mesh_airtime_calc(struct ieee80211_node *ni)
3356: {
...
3366:     rate = ni->ni_txrate;
3367:     overhead = ieee80211_compute_duration(ic->ic_rt,
3368:         ifp->if_mtu + IEEE80211_MESH_MAXOVERHEAD, rate, 0) << M_BITS;
...
3383:     res = (overhead + (nbits / rate)) *       /* <-- div by rate */
3384:         ((1 << S_FACTOR) / ((1 << M_BITS) - errrate));
...
3386:     return (uint32_t)(res >> S_FACTOR);
3387: }

There is no guard against rate == 0. rate is ni->ni_txrate, which is 0 for a freshly discovered mesh neighbour whose transmit rate has not yet been set.

Reachability (confirmed from source)

mesh_airtime_calc(ni) is called from mesh_recv_action_meshlmetric() at line 2560:

2558:     if (ie->lm_flags & IEEE80211_MESH_LMETRIC_FLAGS_REQ) {
2559:         lm_rep.lm_flags = 0;
2560:         lm_rep.lm_metric = mesh_airtime_calc(ni);

This is the mesh Link-Metric request action handler β€” invoked when a remote mesh peer sends a Link Metric Report Request action frame. The handler is registered unconditionally in the mesh action dispatch table (ieee80211_mesh.c:586) and is reached via ieee80211_recv_mgmt β†’ ieee80211_parse_action for any incoming mesh-category action frame. There is no established-peer requirement gating the mesh_airtime_calc call β€” a single crafted action frame from a neighbour whose ni_txrate is still 0 drives nbits / rate with rate == 0 β†’ divide-by-zero β†’ kernel panic.

(Note: ieee80211_compute_duration(..., rate=0, ...) at line 3367 is reached first; if it too divides by rate it panics there. Either way a remote single frame β†’ panic.)

Why not runtime-tested here

No 802.11 radio hardware β†’ no mesh vap β†’ the action-frame receive path (and thus mesh_airtime_calc) cannot be exercised from a real frame. The div-by-zero is definitively confirmed by the source trace: rate = ni->ni_txrate with no zero guard before nbits / rate.

Realistic impact ceiling

Remote, unauthenticated kernel panic (DoS). A single Mesh Link-Metric Request action frame addressed to a node with ni_txrate == 0 divides by zero and panics the kernel. This is the worst of the mesh cluster (DF-0286 is the read-only gateway; DF-0287 is the panic).

Fix

findings/poc/DF-0287/fix.diff adds if (rate == 0) return IEEE80211_MESHLMETRIC_INITIALVAL; immediately after rate = ni->ni_txrate;, bailing with the initial metric until a real rate is set. Verified git apply --check clean and compiles into the base kernel (nativekernel, with the DF-0275/0286 fixes). fix_status: not_testable (diff applies + compiles; runtime not exercisable without WiFi HW).

Fix verification

not_testable

compile validated

module/kernel build rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

Source-confirmed. mesh_airtime_calc nbits/rate with rate=ni_txrate=0 -> div-by-zero panic. No WiFi HW. Remote DoS.