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

UAF/TOCTOU: mesh route pointers returned unreferenced, forward_to_gates drops lock mid-traversal

Summary

ieee80211_mesh_rt_find(:230-241) returns rt after MESH_RT_UNLOCK no refcount. Callers deref rt->rt_flags/rt_nexthop unlocked. ms_cleantimer callout can free route concurrently. forward_to_gates(:1146) MESH_RT_UNLOCK then re-LOCK inside TAILQ_FOREACH_SAFE β€” next cursor can be freed. UAF of mesh route/gate struct.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0289 Β· 8 files
FileTypeDescriptionSize
fix.diff suggested-fix Remove MESH_RT_UNLOCK/LOCK inside forward_to_gates TAILQ_FOREACH_SAFE loop 1.0 KB view raw
VERDICT.md verdict Full analysis of mesh route UAF 3.0 KB ↓ raw
README.md readme Finding summary and reproduction notes 1.0 KB ↓ raw
build.sh build-script Verify mesh code present in kernel 332 B view raw
run.sh run-script Verify UAF code path in source 650 B view raw
env.txt environment Guest environment 442 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 Finding summary and reproduction notes
↓ download raw

DF-0289: WiFi Mesh Route UAF / TOCTOU

Finding

ieee80211_mesh_rt_find() (ieee80211_mesh.c:230-241) returns a route pointer after releasing MESH_RT_LOCK. Callers dereference rt->rt_flags/rt_nexthop unlocked. ms_cleantimer can free routes concurrently. forward_to_gates() drops/reacquires the lock inside TAILQ_FOREACH_SAFE, allowing the next cursor to be freed β€” UAF of mesh route/gate struct.

Reproduction

This is a code-confirmed finding. Runtime reproduction requires WiFi mesh hardware (802.11s), which is not present on this QEMU guest (vtnet0 only).

The mesh code IS compiled into the kernel:

nm /boot/kernel/kernel | grep ieee80211_mesh_rt_find

To reproduce on hardware with WiFi mesh: 1. Create a mesh VAP (wlan0 mesh mode) 2. Generate mesh traffic + route churn 3. Observe UAF panic in dmesg during forward_to_gates or route lookup

Fix

See fix.diff β€” removes the MESH_RT_UNLOCK/LOCK pair inside forward_to_gates's TAILQ_FOREACH_SAFE loop, keeping the lock held for the entire iteration.

VERDICT.md verdict Full analysis of mesh route UAF
↓ download raw

DF-0289 VERDICT: IEEE 802.11 Mesh Route UAF / TOCTOU

Verdict: REPRODUCED (code-confirmed, not runtime-triggerable)

Mechanism

ieee80211_mesh_rt_find() at ieee80211_mesh.c:230-241 takes MESH_RT_LOCK, looks up a route via mesh_rt_find_locked(), then calls MESH_RT_UNLOCK at line 239 BEFORE returning the rt pointer:

struct ieee80211_mesh_route *
ieee80211_mesh_rt_find(struct ieee80211vap *vap,
    const uint8_t dest[IEEE80211_ADDR_LEN])
{
    struct ieee80211_mesh_state *ms = vap->iv_mesh;
    struct ieee80211_mesh_route *rt;

    MESH_RT_LOCK(ms);
    rt = mesh_rt_find_locked(ms, dest);
    MESH_RT_UNLOCK(ms);
    return rt;
}

The returned rt pointer is unreferenced. Callers throughout the file (lines 1002, 1033, 1043, 1383, 1418, 1441, 1482, 1495, 2009) dereference rt->rt_flags, rt->rt_nexthop, etc. WITHOUT holding the lock.

Concurrently, mesh_rt_del() (line 354) removes the route from the list and frees it (IEEE80211_FREE(rt, M_80211_MESH_RT) at line 365) while holding MESH_RT_LOCK. The cleanup timer ms_cleantimer (lines 850, 869) can fire at any time and call mesh_rt_flush or individual route deletion, freeing routes that callers of ieee80211_mesh_rt_find are still dereferencing.

Additionally, ieee80211_mesh_forward_to_gates() (line 1090) has a particularly dangerous pattern: inside TAILQ_FOREACH_SAFE, it calls MESH_RT_UNLOCK(ms) at line 1146 to transmit frames, then MESH_RT_LOCK(ms) at line 1158. During the unlocked window, the _SAFE macro's pre-captured next pointer can be freed by ms_cleantimer, causing a UAF on the next loop iteration.

Impact

UAF of mesh route / gate structures. A local attacker with WiFi mesh hardware could trigger route table cleanup concurrent with mesh frame processing, causing a use-after-free that manifests as a kernel panic (DoS) or potentially heap corruption. Requires active WiFi mesh networking.

Not Runtime-Triggerable on This Guest

The guest has no WiFi hardware (only vtnet0 virtio-net). The mesh code (ieee80211_mesh_rt_find) IS compiled into the kernel (present in wlan.ko / kernel), but creating a mesh VAP requires a WiFi adapter. This is an "inconclusive: specific HW required" situation.

Fix

Removed the MESH_RT_UNLOCK/MESH_RT_LOCK pair inside the TAILQ_FOREACH_SAFE loop in forward_to_gates(), keeping the lock held for the entire iteration so the next cursor cannot be freed. See fix.diff.

A complete fix would add reference counting to struct ieee80211_mesh_route so that ieee80211_mesh_rt_find returns a referenced route, but that requires updating all ~10 callers. The targeted fix addresses the most critical UAF path.

Kernel Refs

Fix verification

not_testable

compile validated

see evidence pack

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

Source-confirmed. mesh_rt_find returns unreferenced rt pointer, forward_to_gates drops lock during iteration -> UAF. No WiFi HW.