Missing length validation in mesh action frame handler: OOB read of stale data
Summary
mesh_recv_action_meshlmetric(:2548) casts frm+2 to meshlmetric_ie without checking efrm-frm>=2+sizeof(ie)(8). parse_action only guarantees 2 bytes. Truncated action -> reads up to 6 bytes past valid frame body. Gateway to DF-0287 div-by-zero.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-0286 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | source trace: OOB read of meshlmetric_ie past 2-byte body | 3.4 KB | β raw |
| README.md | readme | claim, runtime status, reproduce (needs WiFi HW), fix | 1.2 KB | β raw |
| fix.diff | suggested-fix | add efrm-frm length check before cast in mesh_recv_action_meshlmetric | 1.0 KB | 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-0286 β Missing length validation in mesh action frame handler (OOB read)
Claim
mesh_recv_action_meshlmetric() (ieee80211_mesh.c:2548) casts frm+2 to
struct ieee80211_meshlmetric_ie * and reads ie->lm_flags / ie->lm_metric
without checking efrm-frm >= 2 + sizeof(ie). ieee80211_parse_action()
guarantees only sizeof(struct ieee80211_action) = 2 bytes; the mesh category
has no extra length check. A truncated action frame β up to ~7 bytes OOB read of
stale mbuf data. Gateway to DF-0287.
Runtime status
NOT runtime-testable β no 802.11 hardware. The bug is definitively
confirmed by source trace (VERDICT.md): the cast/read at frm+2 with only a
2-byte body guarantee reads lm_flags(off 2) and lm_metric(off 3..6) past the
valid frame.
Reproduce (requires WiFi hardware)
Inject a truncated Mesh Link-Metric action frame (category=MESH, action=LMETRIC,
body shorter than 2 + sizeof(meshlmetric_ie)) at a mesh node. The handler
reads past the body. Not exercisable on this guest.
Fix
fix.diff adds if (efrm - frm < 2 + sizeof(struct ieee80211_meshlmetric_ie))
return 0; at the top of the handler before the cast. Applies + compiles
(nativekernel).
DF-0286 β VERDICT
Verdict: NOT RUNTIME-TESTABLE on this guest (no WiFi hardware) β source trace DEFINITIVELY CONFIRMS the bug is real.
The claim
sys/netproto/802_11/wlan/ieee80211_mesh.c, mesh_recv_action_meshlmetric()
(line 2548):
2548: static int
2549: mesh_recv_action_meshlmetric(struct ieee80211_node *ni,
2550: const struct ieee80211_frame *wh,
2551: const uint8_t *frm, const uint8_t *efrm)
2552: {
2553: const struct ieee80211_meshlmetric_ie *ie =
2554: (const struct ieee80211_meshlmetric_ie *)
2555: (frm+2); /* action + code */
2556: struct ieee80211_meshlmetric_ie lm_rep;
2557:
2558: if (ie->lm_flags & IEEE80211_MESH_LMETRIC_FLAGS_REQ) {
2559: lm_rep.lm_metric = mesh_airtime_calc(ni); /* -> DF-0287 */
...
The handler casts frm+2 to struct ieee80211_meshlmetric_ie * and immediately
reads ie->lm_flags without checking that efrm-frm >= 2 +
sizeof(struct ieee80211_meshlmetric_ie).
What the caller actually guarantees
mesh_recv_action_meshlmetric is reached via the mesh action-frame dispatch
table (ieee80211_mesh.c:586). It is called from ieee80211_parse_action()
(ieee80211_input.c:754), which validates the frame body with:
770: IEEE80211_VERIFY_LENGTH(efrm - frm,
771: sizeof(struct ieee80211_action), return EINVAL);
struct ieee80211_action is the 2-byte {category, action} header β so the
caller guarantees only 2 bytes of frame body. For the mesh action category
there is no additional IEEE80211_VERIFY_LENGTH (the length-check switch in
ieee80211_parse_action covers only CAT_BA and CAT_HT, not mesh). The mesh
handler is then handed frm/efrm with as few as 2 valid bytes.
The OOB read (confirmed from source)
struct ieee80211_meshlmetric_ie (ieee80211_mesh.h:122), __packed:
| field | bytes | offset-in-IE |
|---|---|---|
| lm_ie | 1 | 0 |
| lm_len | 1 | 1 |
| lm_flags | 1 | 2 |
| lm_metric (u32) | 4 | 3 |
| total | 7 |
The IE is read starting at frm+2. With only 2 valid body bytes (frm[0],
frm[1]), the reads of ie->lm_flags (at frm+2) and ie->lm_metric
(frm+3..frm+6) are up to ~5-7 bytes past the valid frame body β reading
stale mbuf residue. This is a remote, unauthenticated OOB info-leak of up to a
handful of bytes (and it is also the gateway to DF-0287: a crafted
lm_flags & REQ triggers mesh_airtime_calc on a neighbour whose ni_txrate
may be 0).
Why not runtime-tested here
No 802.11 radio hardware β no mesh vap β the action-frame receive path cannot be exercised. The OOB read is definitively confirmed by the source trace above.
Realistic impact ceiling
Remote, unauthenticated OOB read of up to ~7 bytes of mbuf residue per crafted truncated Mesh Link-Metric action frame; low-value info leak. More seriously it is the gateway to DF-0287 (the div-by-zero), which is a remote DoS.
Fix
findings/poc/DF-0286/fix.diff adds an explicit length check at the top of
mesh_recv_action_meshlmetric: if (efrm - frm < 2 +
sizeof(struct ieee80211_meshlmetric_ie)) return 0; before the cast/read.
Verified git apply --check clean and compiles into the base kernel
(nativekernel, with the DF-0275/0287 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 action frame frm+2 cast to meshlmetric_ie no length check -> ~7B OOB read. No WiFi HW.
No comments yet.