ichsmb_pci.c:175 wires device_detach to ichsmb_detach, whose device_delete_child() return is ignored (ichsmb.c:689) before unconditional IRQ/IO teardown, lockuninit and a lying success return β DF-5544/5545/5562 family residue, with every deterministic veto path caught one level up (live-proven)
Summary
The PCI glue registers ichsmb_detach, which discards device_delete_child's return then unconditionally releases resources + lockuninit + returns 0 - the family teardown-under-veto shape. UNLIKE uhci/xhci/ohci it is NOT deterministically triggerable today: ichsmb_detach checks bus_generic_detach first, smbus_detach checks its own cascade, smb_detach never vetoes, and second-phase detach no-ops. Live-proven on the q35 rig: veto child -> kldunload fails 'Device busy' with irq+IO fully intact (contrast DF-5544's swallowed veto + freed softc + trap 12); noted collateral - the vetoed unwind still detaches smb0/smb1 and removes /dev/smb* (generic non-transactional detach). Residual: root-vs-root race or a future vetoing smbus driver. check+propagate fix mirrors the family fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5598 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| veto.c | β | 3.9 KB | view raw | |
| Makefile | β | 98 B | β download | |
| build.sh | β | 138 B | view raw | |
| build.log | β | 1002 B | view raw | |
| run.sh | β | 144 B | view raw | |
| run.log | β | 2.1 KB | view raw | |
| env.txt | β | 675 B | view raw | |
| fix.diff | β | 332 B | view raw | |
| VERDICT.md | β | 5.8 KB | β raw | |
| README.md | β | 2.5 KB | β raw | |
| verdict.json | β | 4.6 KB | view raw |
DF-5598 β ichsmb detach-veto family residue (Info, hardening)
File: sys/bus/smbus/ichsmb/ichsmb_pci.c (pass 2)
Class: detach-veto family (DF-5544 / DF-5545 / DF-5562 / DF-5528 / DF-4558) β mitigated variant
What this pack demonstrates
ichsmb_pci.c:175 wires device_detach to ichsmb_detach()
(ichsmb.c:680), whose device_delete_child(dev, sc->smb) return at
ichsmb.c:689 is ignored before the unconditional
ichsmb_release_resources() + lockuninit() + return 0. This is the
family shape β but unlike uhci/xhci/ohci, ichsmb_detach first runs a
checked bus_generic_detach(dev) cascade (ichsmb.c:686) and
smbus_detach() checks its own cascade (smbus.c:110-112).
This harness attaches a vetoing child (EBUSY) directly under smbus0
(grandchild of ichsmb0) and drives the exact kldunload path
(linker_file_unload -> devclass_delete_driver, subr_bus.c:897).
Build (inside the guest)
sh build.sh # make KERNBUILDDIR=/usr/obj/usr/src/sys/X86_64_GENERIC
Requires: q35 rig guest (-machine q35 -device ipmi-bmc-sim,id=bmc0 -device
smbus-ipmi,bmc=bmc0,address=0x20 -device i2c-ddc,address=0x50),
kldload ichsmb, kldload smb.
Run (as root, inside the guest)
sh run.sh
Expected output
kldunload ichsmbfails (Device busy) while the veto child is armed:df5598veto0: DETACH VETO: returning EBUSYon the console, anddevinfo -rstill showsichsmb0withI/O ports 0x700-0x73fandirq 16β the veto is HONORED, nothing is torn down, no panic. (This is the opposite of DF-5544, where the same trigger produceduhci0: detached+ return 0 + freed softc + fatal page fault.)- Collateral observed:
smb0/smb1are detached (their/dev/smb*nodes removed) before the veto surfaces β a vetoed unload leaves the SMBus service dead until a successful retry (generic newbus non-transactional detach; robustness note, not memory corruption). - After
sysctl hw.df5598_armed=0,kldunload ichsmbreturns 0 and the whole subtree (df5598veto0,smbus0,ichsmb0) detaches cleanly.
Artifacts
veto.c,Makefileβ the KLD stand-in veto child (adapted from the DF-5544 harness; the kernel thread is unnecessary becausekldunloadis a stock syscall-level trigger here).build.sh,build.logβ build transcript.run.sh,run.logβ full decisive run.fix.diffβ check + propagatedevice_delete_child()(hardening).env.txt,VERDICT.md,manifest.json,verdict.json.
DF-5598 VERDICT β detach-veto family residue on ichsmb: NOT the uhci bug
Bottom line
not_reproduced / impact none / certain. The DF-5544/5545/5562 family
failure (deterministic teardown-under-veto) does not manifest on the
ichsmb PCI glue: every deterministic veto in the subtree is caught one
level up by the checked bus_generic_detach() cascade, so
ichsmb_release_resources() never runs under a vetoing child. The
ignored device_delete_child() return at ichsmb.c:689 (reached via the
DEVMETHOD(device_detach, ichsmb_detach) wiring at ichsmb_pci.c:175)
is a genuine newbus-contract violation and is kept as an Info
defense-in-depth finding consistent with the family sweep.
Why the family bug is unreachable here (code)
ichsmb_detach(ichsmb.c:686-688) checksbus_generic_detach(dev)and returns the error before any teardown.bus_generic_detach(subr_bus.c:2867-2880) detaches all children, cascading.- The only child is
smbus0(ichsmb.c:114); itssmbus_detach(smbus.c:106-115) checks its ownbus_generic_detachover thesmb0..smbN(and any other) children. - The in-tree leaf
smb_detach(smb.c:147-155) never vetoes β it removes the devfs node and returns 0 unconditionally, even with/dev/smbNopen (mode 0600 root anyway). - After a successful
bus_generic_detach, the second-phasedevice_detach(child)insidedevice_delete_child(subr_bus.c:1292) is a no-op (state != DS_ATTACHED -> return 0,subr_bus.c:2136-2137), so no in-tree veto can surface there. - The
DS_BUSYearly-EBUSY (subr_bus.c:2134-2135) requiresdevice_busy()on an smbus-subtree device; the only callers in the tree are cxm/bktr/agp/drm/fd β none insys/bus/smbusorsys/dev/smbus.
Residual exposure of the unchecked call (ichsmb.c:689):
* a driver kldloaded onto the smbus bus concurrently with the
kldunload (root-vs-root race) that attaches a child between the checked
generic detach and device_delete_child β its veto would then be
swallowed and ichsmb_release_resources() + lockuninit() would run
under it while device_detach(ichsmb0) reports success;
* any future smbus-bus driver whose detach vetoes only in the
second phase (none possible today, per 4).
Live evidence (q35 + ipmi-bmc-sim rig, ICH9 82801I at 0:31:3)
run.log β decisive run:
kldunload ichsmb -> "kldunload: can't unload file: Device busy" (rc=1) df5598veto0: DETACH VETO: returning EBUSY ... >>> ichsmb0 still attached with resources: veto HONORED ichsmb0 / Interrupt request lines cpu4: 16 / I/O ports 0x700-0x73f (intact) sysctl hw.df5598_armed=0 kldunload ichsmb -> rc=0, df5598veto0/smbus0/ichsmb0 detach cleanly
Serial (dmesg) confirms the unwind order:
smb1: detached -> smb0: detached -> df5598veto0: DETACH VETO -> (unload
aborts, resources intact), then after disarming:
df5598veto0: cooperating -> detached -> smbus0: detached -> ichsmb0:
detached.
Contrast with DF-5544 (same harness pattern, uhci): there the trigger
yielded uhci0: detached, return 0, freed softc and a Fatal trap 12 page
fault. Here: honest EBUSY, zero teardown, guest healthy.
Observed collateral (noted, not filed)
The vetoed unwind still detaches smb0/smb1 before the veto surfaces
(their /dev/smb* devfs nodes are destroyed β verified by the failed
smbmsg checks in run.log), so a vetoed kldunload ichsmb leaves the
SMBus userland interface dead until a successful retry, even though the
controller keeps its IRQ/IO. This is generic newbus non-transactional
detach semantics (the same "retry later" posture DF-5544's fix embraces),
not a memory-safety defect, and it is not re-filed separately.
Fix
fix.diff β propagate device_delete_child()'s error before touching
resources (3 lines, mirrors the family fix). Not kernel-rebuild-validated:
there is no reproducible bad behavior to A/B on this rig (that is the
point of the finding), so fix_status=not_testable; the diff is trivially
reviewable and matches the validated DF-5544/5545/5562 fix shape.
Negative results recorded during this pass (pass-2 depth)
- Probe table walk bounded/NULL-terminated (
ichsmb_pci.c:210-215); duplicate ICH7/8/9 rows (:121-126) are cosmetic first-match-wins. - No revision/quirk dispatch exists (checklist item c): DID-only match at
ichsmb_pci.c:211β nothing attacker-shaped to reach. ICH_HOSTCbyte write atichsmb_pci.c:255clobbersSMB_SMI_EN/I2C_EN(ichsmb_reg.h:53-56) β firmware-config destruction only; no attacker control, no kernel-memory consequence. It also happens beforebus_setup_intr(ichsmb.c:124), but no SMBus transaction source is armed beforesmbus_attach's probing (smbus.c:94-100) which runs after the handler install β window benign. HOSTC is neither restored on attach failure nor disabled on detach (no shutdown method,ichsmb_pci.c:171-193): controller leftHST_ENwith IRQ released after unload β real-HW robustness smell (unhandled SMBALERT# level IRQ), Info-grade, recorded here rather than filed.- Attach error unwinding at the PCI level (
ichsmb_pci.c:258-266) is sound; the deeper ichsmb_attach unwinding bugs are DF-5460's (not re-reported). RF_SHAREABLEIRQ (ichsmb_pci.c:246-247) with a spurious-safe handler (ichsmb.c:509-518) β OK.- No copyin/copyout, no lengths, no locks in this file.
bus_generic_detach'sTAILQ_FOREACHvs concurrentdevice_add_child(subr_bus.c:2875) β generic newbus root-vs-root race, not file-specific.
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_testableNo reproducible bad behavior exists to A/B (the finding's substance is that the deterministic family failure does NOT reach the teardown); fix.diff is the trivial 3-line check+propagate identical in shape to the already-validated DF-5544/5545/5562 fixes and is supplied for review completeness.
fix.diff; family precedent run.fix.log in findings/poc/DF-5544/
Confirmed kernel references
Detail
Evidence (decisive lines)
run.log (kldunload rc=1 'Device busy', devinfo -r shows ichsmb0 irq 16 + 0x700-0x73f intact after the vetoed attempt, clean rc=0 after hw.df5598_armed=0); dmesg tail in run.log (smb1/smb0 detached -> 'df5598veto0: DETACH VETO: returning EBUSY' -> abort; then 'cooperating -> detached -> smbus0: detached -> ichsmb0: detached'); veto.c/build.sh/run.sh harness; VERDICT.md for the full code-level veto-propagation analysis
PoC changes
Adapted the proven DF-5544 veto harness: (1) parent bus is smbus (child = grandchild of ichsmb0) instead of uhci; (2) no kernel thread needed -- stock 'kldunload ichsmb' is the devclass_delete_driver() trigger (the DF-5544 thread existed only to dodge the sysctl-lock deadlock of a direct device_detach() call); (3) -Werror fixes: dropped volatile on the sysctl-backed int, added
Verified recommended fix
Check and propagate device_delete_child()'s return at ichsmb.c:689 before ichsmb_release_resources(), so a second-phase child-deletion failure leaves IRQ/IO/softc fully intact and the caller retries (matches the validated DF-5544/5545/5562 family fix).
Verdict
ichsmb_pci.c:175 wires device_detach to ichsmb_detach(), which ignores device_delete_child()'s return (ichsmb.c:689) before the unconditional ichsmb_release_resources() + lockuninit() + 'return 0' -- the DF-5544/5545/5562 family shape. But unlike uhci/xhci/ohci, every deterministic veto in the ichsmb subtree is caught one level up: ichsmb_detach CHECKS bus_generic_detach() (ichsmb.c:686) and smbus_detach checks its own cascade (smbus.c:110-112), the only leaf smb_detach() never vetoes (smb.c:147-155), and the second-phase device_detach inside device_delete_child is a no-op for already-detached devices (subr_bus.c:2136-2137; DS_BUSY dead -- no device_busy() callers in the smbus subtree). Proven live on the q35+ipmi-bmc-sim rig (real ICH9 82801I): with a KLD veto child (EBUSY) under smbus0, 'kldunload ichsmb' honestly fails 'Device busy', ichsmb0 stays attached with irq 16 + IO 0x700-0x73f fully intact, no panic -- the exact opposite of DF-5544's swallowed veto + freed softc + fatal page fault. After disarming, the unload completes cleanly. Residual exposure of the unchecked call: a driver kldloaded onto the smbus bus racing the kldunload (root-vs-root) between the checked generic detach and device_delete_child, or a future vetoing smbus-bus driver; hence Info hardening, not a reachable memory-safety bug.
No comments yet.