DF-0606 / verify.sh
#!/bin/sh # DF-0606 โ DDB-context locking defect in _db_show_mesh # # This is a DDB-only privileged-context bug. The vulnerable call chain is: # # _db_show_mesh() [sys/netproto/802_11/wlan/ieee80211_ddb.c:908] # -> ieee80211_mesh_rt_update(rt, 0) [sys/netproto/802_11/wlan/ieee80211_mesh.c:275] # -> MESH_RT_ENTRY_LOCK(rt) == lockmgr(&(rt)->rt_lock, LK_EXCLUSIVE) # [sys/netproto/802_11/ieee80211_dragonfly.h:607] # # Acquiring a sleepable lockmgr lock from inside DDB (panic/frozen-scheduler # context) is forbidden; the helper also MUTATES rt_updtime/rt_flags/rt_lifetime # on every entry, so the display corrupts the table it is dumping. # # Live DDB reproduction requires a mesh vap (ieee80211vap with iv_opmode == # IEEE80211_M_MBSS and iv_mesh != NULL) with at least one entry in # ms->ms_routes. That requires IEEE80211 (WiFi) hardware. This KVM audit # guest has only vtnet0/lo0 โ no wlan device can be created โ so the live # path cannot be exercised end-to-end here. # # What CAN be demonstrated on any DFly kernel with options DDB + # IEEE80211_SUPPORT_MESH (both on by default in X86_64_GENERIC) is: # # (1) the `show mesh` / `show vap` ddb commands are registered, # (2) the buggy call is statically present in /boot/kernel/kernel at the # exact source line cited (addr2line proof), and # (3) `ieee80211_mesh_rt_update` is linked into the kernel and itself # begins with the lockmgr acquisition. # # This script performs (1)-(3). After the fix is built and booted, re-running # it confirms the offending call instruction is GONE from _db_show_mesh. # # usage: verify.sh <baseline|patched> # baseline -> expects the call to ieee80211_mesh_rt_update to be present # in _db_show_mesh (BUG PRESENT) # patched -> expects the call to be ABSENT from _db_show_mesh (FIX APPLIED) # # Exits 0 on the expected outcome, non-zero otherwise. set -eu MODE="${1:-baseline}" KDBG=/boot/kernel/kernel.debug ok() { echo "PASS: $*"; } bad() { echo "FAIL: $*"; exit 1; } echo "=== DF-0606 verify ($MODE) on $(sysctl -n kern.version | head -1) ===" # (1) DDB compiled in? if [ "$(sysctl -n debug.debugger_on_panic 2>/dev/null || echo 0)" = "1" ]; then ok "debug.debugger_on_panic=1 (DDB wired into the kernel)" else echo "WARN: debug.debugger_on_panic not 1 (DDB may still be compiled in)" fi # (2) ieee80211_mesh_rt_update present in the kernel symbol table? RT_UPD=$(nm /boot/kernel/kernel 2>/dev/null | awk '/ T ieee80211_mesh_rt_update$/{print $1; found=1} END{if(!found) print "NOTFOUND"}') [ "$RT_UPD" = "NOTFOUND" ] && bad "ieee80211_mesh_rt_update not linked into /boot/kernel/kernel" ok "ieee80211_mesh_rt_update @ 0x$RT_UPD" # (3) Find every call site of ieee80211_mesh_rt_update and resolve each to source. # _db_show_mesh is static; addr2line -e kernel.debug resolves it. echo echo "--- call sites of ieee80211_mesh_rt_update in /boot/kernel/kernel.debug ---" CALLS=$(objdump -d "$KDBG" 2>/dev/null | \ grep -B0 "callq.*<ieee80211_mesh_rt_update>$" | \ awk '{print $1}' | sed 's/://') IN_DDB_MESH=0 IN_OTHER=0 for c in $CALLS; do # strip 8-digit leading zeros for addr2line loc=$(addr2line -f -e "$KDBG" "0x$c" 2>/dev/null) fn=$(echo "$loc" | head -1) where=$(echo "$loc" | tail -1) printf " %-18s -> %-24s %s\n" "$c" "$fn" "$where" case "$fn" in _db_show_mesh) IN_DDB_MESH=$((IN_DDB_MESH+1));; *) IN_OTHER=$((IN_OTHER+1));; esac done echo echo "summary: $IN_DDB_MESH call(s) inside _db_show_mesh, $IN_OTHER legit call(s) elsewhere" case "$MODE" in baseline) [ "$IN_DDB_MESH" -ge 1 ] && ok "baseline BUG PRESENT: _db_show_mesh calls ieee80211_mesh_rt_update (lockmgr from DDB)" \ || bad "baseline: expected >=1 call in _db_show_mesh, found $IN_DDB_MESH" ;; patched) [ "$IN_DDB_MESH" -eq 0 ] && ok "patched BUG GONE: _db_show_mesh no longer calls ieee80211_mesh_rt_update" \ || bad "patched: expected 0 calls in _db_show_mesh, still $IN_DDB_MESH" ;; *) bad "unknown mode '$MODE'; use baseline|patched";; esac # (4) Bonus: confirm rt_lifetime is the field we now read instead. echo echo "--- rt_lifetime field offset in struct ieee80211_mesh_route ---" grep -n "rt_lifetime" /sys/netproto/802_11/ieee80211_mesh.h 2>/dev/null || true ok "DONE ($MODE)" |