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

amdsmb_detach performs no quiesce/drain: kldunload during an in-flight locked transaction runs lockuninit() on a held lock and releases the I/O resource under live bus_read_1/bus_write_1 (post-release port I/O)

Summary

Detach deletes the child then immediately lockuninits and releases the io resource; /dev/smb teardown only removes minors and the callback is a no-op, so nothing waits for a thread holding sc->lock across the up-to-5.4s in-lock spin (effectively unbounded via DF-5506's dead timeout): lockmgr state corrupted on a held lock + port I/O on a released resource. Root-gated kldunload race; trace-proven only (rig drives code without newbus). Drain-before-uninit fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5508 Β· 3 files
FileTypeDescriptionSize
README.md β€” 2.2 KB ↓ raw
verdict.json β€” 2.5 KB view raw
env.txt β€” 340 B view raw

DF-5508 β€” amdsmb_detach performs no quiesce/drain: kldunload during an in-flight (locked) transaction lockuninit()s a held lock and releases the I/O resource under live MMIO

Trace-proven lifecycle gap (Info, root-gated, hardware-gated β€” not executable on any available rig; see verdict.json).

Trace

amdsmb_detach (sys/bus/smbus/amdsmb/amdsmb.c:175-191):

  1. device_delete_child(dev, sc->smbus) tears down the smbus bus and its smb children. The /dev/smbN cdev teardown (sys/dev/smbus/smb/smb.c:151-152, dev_ops_remove_minor) removes devfs entries but nothing waits for threads already inside smbioctl β€” and this driver's amdsmb_callback (amdsmb.c:193-207) makes SMB_REQUEST_BUS a no-op, so the smbus layer provides no serialization either. The only exclusion is the driver's own sc->lock.
  2. A thread in e.g. amdsmb_bread holds AMDSMB_LOCK(sc) across the entire transaction (amdsmb.c:527-544), including the up-to-5.4 s amdsmb_wait busy spin (amdsmb.c:287-291) β€” a wide window.
  3. kldunload then reaches lockuninit(&sc->lock) (amdsmb.c:185) on a lock that is still held, followed by bus_release_resource (amdsmb.c:186-188) while the in-flight thread continues bus_read_1/bus_write_1 on the released I/O range β€” use of a freed resource / potential I/O to a reassigned device.

Same shape as ichsmb's DF-5460 (Info) β€” that sibling at least had an interrupt handler to leak; here the exposure is the lock-state corruption plus post-release port I/O. Triggering requires an open /dev/smbN fd with an ioctl in flight against stuck/absent hardware AND concurrent kldunload amdsmb β€” both root-only on a stock system, hence Info.

Related, folded here (below finding threshold): amdsmb_attach ignores the return of bus_generic_attach (amdsmb.c:170) β€” a failed smbus child attach is reported as success; harmless bookkeeping.

Suggested fix (prose)

Before lockuninit, drain in-flight ops: e.g. set a detaching flag under the lock, take the lock once (lockmgr(&sc->lock, LK_EXCLUSIVE | LK_DRAIN) style or a state flag checked by the op wrappers), and have amdsmb_* entry points return ENXIO once detaching. Check bus_generic_attach's return in attach.

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

Not testable on this rig (no AMD-8111 device; race requires real newbus attach + kldunload timing).

per-fix-DF-5508

Confirmed kernel references

Detail

Evidence (decisive lines)

README.md trace with path:line; ichsmb sibling DF-5460 (Info) for family pricing

PoC changes

no PoC β€” trace-only (root-gated + hardware-gated race; Info severity)

Verified recommended fix

Drain in-flight ops before lockuninit (detaching flag + LK_DRAIN-style lock acquisition; op wrappers return ENXIO once detaching); check bus_generic_attach return in attach.

Verdict

Trace-proven lifecycle gap, not executable on any available rig (AMD-8111 hardware-gated; the harness rig of DF-5506 drives the code paths directly and cannot reproduce a kldunload-vs-ioctl race without the real newbus attach). amdsmb_detach (amdsmb.c:175-191) does not drain in-flight transactions: /dev/smbN teardown does not wait for threads inside smbioctl (smb.c:151-152 removes devfs minors only) and amdsmb_callback is a no-op (amdsmb.c:193-207), so a thread holding sc->lock inside the up-to-5.4s amdsmb_wait spin (amdsmb.c:287-291) is still running when kldunload reaches lockuninit(&sc->lock) (amdsmb.c:185) β€” lockmgr state corruption on a held lock β€” and then bus_release_resource (amdsmb.c:186-188) frees the I/O range under live bus_read_1/bus_write_1 use (post-release port I/O to a potentially reassigned device). Requires open /dev/smbN fd + in-flight ioctl + concurrent kldunload, all root-only: Info severity, speculative execution but likely correctness, certain code-shape. Folded below threshold: attach ignores bus_generic_attach return (amdsmb.c:170).