Single-caller assumption unenforced: ichsmb_callback no-ops bus request/release, so concurrent /dev/smb ioctls interleave in the transaction state machine and panic KASSERT(sc->ich_cmd == -1)
Summary
The comment claims the smbus layer serializes; the callback returns success for REQUEST/RELEASE with no arbitration and smbus_request_bus adds none - fork() shares the fd and two threads interleave the state machine (lksleep drops the mutex mid-transaction; bwrite's block state is written pre-mutex): LIVE-REPRODUCED TWICE on the q35 rig ('panic: ichsmb_bread: ich_cmd=0' with two racing frames, and a quick-variant with a SECONDARY PANIC on another CPU, guest wedged both times). A callback-based fix attempt was honestly disproven live (unbalanced release panic); xfer_lock-across-each-method fix validated 3/3 clean 4-way races.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5459 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| df5457_poc.c | β | 7.8 KB | view raw | |
| panic.txt | β | 604 B | view raw | |
| panic2.txt | β | 926 B | view raw | |
| baseline_run.log | β | 1.9 KB | view raw | |
| fixed_race_x3.log | β | 404 B | view raw | |
| fixed_run.log | β | 1.5 KB | view raw | |
| fix.diff | β | 7.2 KB | view raw | |
| build.sh | β | 107 B | view raw | |
| run.sh | β | 154 B | view raw | |
| env.txt | β | 496 B | view raw | |
| qemu_cmdline.txt | β | 392 B | view raw |
Fix verification
fixedBaseline modules: 2/2 race runs panic (panic.txt, panic2.txt). Patched ichsmb.ko+smb.ko rebuilt in-guest from fix.diff: 3/3 race runs clean, guest alive, zero panic/lockmgr dmesg lines (fixed_race_x3.log).
fixed_race_x3.log; fixed_run.log; build output in VERDICT.md
Confirmed kernel references
Detail
Exploit chain
root (or wheel with 0600 devfs node relaxed) opens /dev/smb0; fork shares the single-open fd; children issue SMB_QUICK_READ/SMB_BREAD/SMB_BWRITE concurrently; second caller enters a method while the first sleeps in ichsmb_wait (lksleep drops sc->mutex) -> KASSERT panic -> DDB wedge. On INVARIANTS-free builds the same interleave corrupts the block state machine instead.
Evidence (decisive lines)
panic.txt (run 1: ichsmb_bread), panic2.txt (run 2: ichsmb_quick + secondary CPU panic), fixed_race_x3.log (3 clean races on patched modules, 'ALL_RACES_DONE_GUEST_ALIVE', dmesg panic/lockmgr count 0), fix.diff
PoC changes
wrote mode 'race' (4 forked fd-sharers, randomized QUICK/BREAD/BWRITE against the QEMU smbus-ipmi BMC at 0x20) into df5457_poc.c; built a q35 rig (first live ichsmb hardware in this audit)
Verified recommended fix
Add sc->xfer_lock (lockinit in ichsmb_attach, uninit in fail/detach) and acquire LK_EXCLUSIVE across the full body of all ten SMBus methods so ich_cmd/block_* state is never visible to a second caller; keep ichsmb_callback stateless.
Verdict
REPRODUCED: concurrent /dev/smb0 ioctls from forked processes sharing one fd interleave inside the unserialized ichsmb transaction state machine (ichsmb_callback no-ops the bus request, ichsmb.c:148-165) and panic the always-compiled KASSERT(sc->ich_cmd == -1) at ichsmb.c:174/391/422 β two baseline runs panicked from two different entry points ('ichsmb_bread: ich_cmd=0' with two racing ichsmb_bread frames, then 'ichsmb_quick: ich_cmd=0' with a SECONDARY PANIC on another CPU). Privileged local DoS (device node 0600 root:wheel). Fix (xfer_lock across each method) validated live: 3/3 races clean on patched modules vs 2/2 panics on baseline.
No comments yet.