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

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)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0286 Β· 8 files
FileTypeDescriptionSize
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
README.md readme claim, runtime status, reproduce (needs WiFi HW), fix
↓ download 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).

VERDICT.md verdict source trace: OOB read of meshlmetric_ie past 2-byte body
↓ download raw

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_testable

compile 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.