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)
PoC verification
Evidence pack
findings/poc/DF-0287 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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 |
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).
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_testablecompile 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.
No comments yet.