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)
PoC verification
Evidence pack
findings/poc/DF-5508 Β· 3 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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):
device_delete_child(dev, sc->smbus)tears down the smbus bus and itssmbchildren. The/dev/smbNcdev teardown (sys/dev/smbus/smb/smb.c:151-152,dev_ops_remove_minor) removes devfs entries but nothing waits for threads already insidesmbioctlβ and this driver'samdsmb_callback(amdsmb.c:193-207) makesSMB_REQUEST_BUSa no-op, so the smbus layer provides no serialization either. The only exclusion is the driver's ownsc->lock.- A thread in e.g.
amdsmb_breadholdsAMDSMB_LOCK(sc)across the entire transaction (amdsmb.c:527-544), including the up-to-5.4 samdsmb_waitbusy spin (amdsmb.c:287-291) β a wide window. kldunloadthen reacheslockuninit(&sc->lock)(amdsmb.c:185) on a lock that is still held, followed bybus_release_resource(amdsmb.c:186-188) while the in-flight thread continuesbus_read_1/bus_write_1on 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_testableNot testable on this rig (no AMD-8111 device; race requires real newbus attach + kldunload timing).
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).
No comments yet.