DF-5157 / verdict.json
{ "finding_id": "DF-5157", "status": "untested", "verdict": "The ath LED blink callout is re-armed after its only teardown cancellation: ath_detach() cancels sc_ledtimer inside ath_stop() (if_ath.c:2703) BEFORE taskqueue_free(sc->sc_tq) (if_ath.c:1416), and taskqueue_free runs all pending tasks (kern/subr_taskqueue.c:151-157), whose tx-completion path calls ath_led_event() (if_ath.c:4570/4628/4676, ungated by sc_running, outside ATH_LOCK) which callout_reset()s the chain again (if_ath_led.c:185). No later cancel or drain exists; the timer fires ath_led_off (if_ath_led.c:166) up to ~500ms later into a detached and then freed softc/HAL (ath_hal_detach at if_ath.c:1435) \u2014 use-after-free (read + indirect call via sc->sc_ah, then a write via ath_led_done). Untestable on the audit guest: QEMU has no Atheros NIC emulation, so ath0 cannot exist; reproduction requires real ath hardware with softled enabled (IBM devids auto-enable, if_ath.c:908, or root sysctl dev.ath.X.softled=1) under tx load during kldunload/hot-unplug.", "reproduced": false, "impact": "none", "confidence": "likely", "exploit_chain": "unproven (hardware-bound): root enables softled on ath NIC -> tx traffic keeps sc_ledtimer armed -> kldunload if_ath / PCI hot-removal while a tx-completion task is queued -> ath_stop cancels the timer -> taskqueue_free drains the task -> ath_led_event re-arms it -> ath_hal_detach frees the HAL, newbus frees the softc -> ath_led_off fires on freed memory (UAF read of sc->sc_ah + indirect call, UAF write of sc->sc_blinking).", "evidence": "VERDICT.md: full cited trace (if_ath.c:1385-1436 ordering, 2703 cancel site, 4570/4628/4676 LED call sites; kern_timeout.c:1032/218 cancel semantics; subr_taskqueue.c:151-157 drain-runs-pending-tasks). env.txt: guest pciconf -l proving no ath device exists.", "kernel_refs": [ "sys/dev/netif/ath/ath/if_ath_led.c:166", "sys/dev/netif/ath/ath/if_ath_led.c:179", "sys/dev/netif/ath/ath/if_ath_led.c:188", "sys/dev/netif/ath/ath/if_ath.c:1411", "sys/dev/netif/ath/ath/if_ath.c:1416", "sys/dev/netif/ath/ath/if_ath.c:2703", "sys/dev/netif/ath/ath/if_ath.c:4570", "sys/kern/subr_taskqueue.c:151" ], "poc_changes": "No PoC authored: no Atheros hardware emulation exists in QEMU, so no trigger program can reach the driver on the audit guest (env.txt). The pass-2 analysis seed had no PoC sketch.", "attempts": 0, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 0, "guest_dirty": 0, "build_cmd": "", "run_cmd": "", "code_hash": "", "notes": "Killed in-file alternatives: period-0 infinite blink (ath_led_done never re-arms; periods not sysctl-settable), sc_invalid gate (set only on attach failure, if_ath.c:1375-1378, before any tx exists \u2014 dead for this purpose), DF-2152/DF-4315 sc_hwmap OOB (known, not re-filed), DF-5092 hal GPIO CfgInput (known, different file). DF callout core verified safe against cancel-vs-rearm races (kern_timeout.c:218-229) \u2014 the defect is purely aths teardown ordering.", "recommended_fix": "Re-cancel (drain) sc_ledtimer in ath_detach() immediately after taskqueue_free(), when no task can re-arm it; optionally also gate ath_led_event()/blink arming on sc_running.", "fix_status": "not_applicable", "fix_baseline_reproduced": false, "fix_patched_reproduced": false, "fix_verdict": "Fix validation not performable on this guest (no ath hardware; baseline cannot reproduce). fix.diff (one callout_cancel after taskqueue_free in ath_detach) applies cleanly with patch(1) against the read-only sys/ tree.", "fix_evidence": "n/a" } |