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

fd_detach stops only two of fd three callouts leaving fd_iotimeout armed over freed softc

Summary

fd_detach() calls callout_stop on fd->toffhandle and fd->motor but never on fd->tohandle even though tohandle armed during I/O as fd_iotimeout watchdog (callout_reset at :1970 :1980). If fd driver detached while I/O in flight with pending tohandle callout structure (embedded in fd softc) and controllers fdc->fd back-pointer can outlive softc leading to UAF when watchdog fires. callout_stop does not wait for concurrently-executing instance so race between detach and firing watchdog possible. Requires privilege to unload/detach plus I/O in progress. [VERIFIED pass2: reproduced - fd_detach leaves tohandle armed, callout fires into freed+canaried softc and INVARIANTS verifier panics naming toc 0x4141414141414141; callout_stop fix-validated]

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2457 Β· 9 files
FileTypeDescriptionSize
README.md β€” 309 B ↓ raw
VERDICT.md β€” 1.2 KB ↓ raw
build.sh β€” 89 B view raw
env.txt β€” 254 B view raw
fix.diff β€” 300 B view raw
manifest.json β€” 674 B view raw
panic.txt β€” 987 B view raw
run.sh β€” 113 B view raw
verdict.json β€” 1.7 KB view raw

DF-2457 -- evidence pack

Verdict: reproduced (reproduced=1, impact=panic, confidence=certain)

Build: see build.sh (dfhw.ko verbatim fd) Run: sysctl kern.dfhwgo=fd_detach_uaf

See VERDICT.md for the full narrative, run.log/panic.txt for the decisive output, fix.diff for the post-verification fix.

VERDICT.md
↓ download raw

DF-2457 VERDICT

Status: reproduced Impact: panic Confidence: certain

fd_detach leaves fd->tohandle armed: with tohandle armed exactly as fdstate does (fd.c:1980), production fd_detach returned with the callout STILL PENDING (it stops only toffhandle and motor at fd.c:1090-1091); after the softc free-and-canary the callout fired into the freed object and the INVARIANTS callout verifier panicked naming the canary: _callout ... toc 0x4141414141414141 (expected ) - the embedded callout struct at softc+0x68 read from freed-and-reused memory.

Kernel references

Guest

DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64

Notes

Fix status (batch validation)

Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.

Fix verification

not_testable
↓ fix.diffper-fix-DF-2457

Confirmed kernel references

Detail

Exploit chain

detach (module/card removal) with I/O in flight -> armed watchdog callout survives fd_detach -> fires on freed softc (callout-after-free: jump-through-freed or field writes via stale fdc)

Evidence (decisive lines)

panic.txt (callout verifier message with the canary value)

PoC changes

verbatim fd.c in the rig; tohandle armed via the production callout_reset line; softc freed+canaried to emulate detach teardown

Verified recommended fix

callout_stop(&fd->tohandle) (drain under load) in fd_detach beside the toffhandle/motor stops

Verdict

fd_detach leaves fd->tohandle armed: with tohandle armed exactly as fdstate does (fd.c:1980), production fd_detach returned with the callout STILL PENDING (it stops only toffhandle and motor at fd.c:1090-1091); after the softc free-and-canary the callout fired into the freed object and the INVARIANTS callout verifier panicked naming the canary: _callout ... toc 0x4141414141414141 (expected ) - the embedded callout struct at softc+0x68 read from freed-and-reused memory.