ipmi2_pci_probe is the only IPMI frontend probe lacking the ipmi_attached singleton guard β double attach (second cdev + second kthread, interleaved KCS/SMIC state machines) on dual-description BMC hardware
Summary
All three sibling probes enforce the singleton; the native-PCI probe does not - on dual-description BMC boards the second attach creates a second cdev+kthread interleaving one KCS/SMIC interface (compounding the known unbounded loops into a wedge). FreeBSD HEAD inherits the omission. Hardware-gated (no PCI IPMI device model in QEMU). Sibling-guard one-liner fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5076 Β· 7 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.3 KB | β raw | |
| VERDICT.md | β | 6.2 KB | β raw | |
| guard_matrix.log | β | 657 B | view raw | |
| env.txt | β | 323 B | view raw | |
| fix.diff | β | 663 B | view raw | |
| manifest.json | β | 1.3 KB | view raw | |
| verdict.json | β | 5.1 KB | view raw |
DF-5076 evidence pack
What
sys/dev/misc/ipmi/ipmi_pci.c β ipmi2_pci_probe (:183-193) is the only
IPMI frontend probe without the ipmi_attached singleton guard (siblings:
ipmi_pci.c:77, ipmi_isa.c:85, ipmi_acpi.c:62). On boards whose BMC is
described twice (SMBIOS/ISA/ACPI/Dell-quirk and native PCI class 0c:07),
the native PCI function attaches a second full IPMI stack (second cdev,
second kthread at ipmi_kcs.c:476 / ipmi_smic.c:382) after the first frontend
already set ipmi_attached=1 (ipmi.c:864) β two state machines interleave on
one BMC β KCS/SMIC handshake corruption β stuck kernel threads (compounding
the known unbounded loops DF-1865/DF-1866/DF-2003). FreeBSD HEAD inherits
the same omission.
Reproduce
Not runnable on this guest: QEMU has no PCI IPMI device model; the guest has
no class-0c:07 PCI function (env.txt). Static proof in guard_matrix.log
(grep of all four probes). Verdict: untested / code-fact-certain, following
the DF-4985/DF-5000 precedent for hardware-gated findings.
Contents
VERDICT.mdβ narrative, consequence chain, negative resultsguard_matrix.logβ static guard matrix across the four frontendsenv.txtβ guest evidence (uname, pciconf: no 0c:07, no AMD GPU, ipmi absent)fix.diffβ add the sibling guard;git apply --checkverifiedmanifest.json,verdict.json
DF-5076 β ipmi2_pci_probe is the only IPMI frontend probe lacking the ipmi_attached re-attach guard β double attach of the IPMI stack on dual-description hardware
File: sys/dev/misc/ipmi/ipmi_pci.c (pass 2, GLM 5.3)
Severity: Low Β· CWE-667 (Improper Locking)/CWE-362-adjacent (unguarded
singleton invariant) Β· confidence: certain (code fact); impact hardware-topology-gated
Status: untested (no PCI IPMI device exists on the QEMU guest β QEMU has no
native-PCI IPMI device model at all; env.txt).
1. The singleton invariant and the family that enforces it
The ipmi stack is a singleton: ipmi.c:65 declares int ipmi_attached = 0;
and ipmi_attach sets ipmi_attached = 1 on every successful attach
(ipmi.c:864). All other frontend probes enforce it before claiming a
device:
ipmi_pci.c:77βipmi_pci_probe(Dell PE2650 1028:000d quirk): guardedipmi_isa.c:85βipmi_isa_probe(SMBIOS/ISA): guardedipmi_acpi.c:62βipmi_acpi_probe(ACPI namespace): guarded
ipmi2_pci_probe β the native PCI IPMI frontend (class 0c:07,
progif SMIC=0/KCS=1/BT=2 per pcireg.h:414-416) β has no guard
(ipmi_pci.c:183-193). It matches any PCI function with
class=0x0c subclass=0x07 regardless of whether another frontend already
attached the (same or another) BMC interface.
2. Consequence chain on dual-description hardware
On a board whose BMC is reachable both through a legacy description (SMBIOS
type 35 β isa; ACPI PNP node; or the Dell PCI quirk dev) and as a native
PCI IPMI function β the exact topology the three sibling guards exist for β
newbus can finish ipmi_attach() on the first frontend (setting
ipmi_attached=1), and the unguarded ipmi2_pci_probe still claims the
native PCI function:
ipmi2_pci_attach(ipmi_pci.c:196-275) maps the native BAR(0) (:223-231), dispatches on progif (KCS βipmi_kcs_probe_align:249,ipmi_kcs_attach:255; SMIC βipmi_smic_attach:262), then callsipmi_attach(dev)(:267) again:- second
config_intrhook_establishβ secondipmi_startuprun (ipmi.c:708) β secondmake_dev("ipmi%d")(ipmi.c:831, unit 1) and a second kthread (ipmi_kcs.c:476/ipmi_smic.c:382) β - when both descriptions point at the same BMC (the historical reason the
guards were added β Dell PE2650-era machines exposed the BMC both via
SMBIOS/ISA and the 1028:000d PCI function), two kcs/smic state machines
now interleave transactions on one KCS/SMIC interface. Interleaving
corrupts the KCS/SMIC handshake, and with this driver's unbounded
reply/error polling loops (DF-1865
ipmi_kcs.c, DF-1866 probe_align, DF-2003ipmi_smic.c) the realistic ceiling is a stuck, CPU-pinning kernel thread β a boot-time or runtime hang, i.e. local/DoS-class impact, not memory corruption.
FreeBSD inherits the identical omission (verified against FreeBSD HEAD
sys/dev/ipmi/ipmi_pci.c: ipmi_pci_probe guarded, ipmi2_pci_probe not),
so this is an upstream-inherited family inconsistency worth reporting to
both projects.
3. Verification performed
- Static proof:
guard_matrix.logβ grep of all four probes. - Guest: not testable β the QEMU guest has no class-0c:07 device
(
pciconf -lin env.txt shows no serial-bus IPMI function), and QEMU provides no PCI IPMI device model to instantiate one; the current guest config doesn't even attach ipmi (no /dev/ipmi*, no dmesg lines β the DF-4777/4948/4978 era used BMC-sim frontends that are not in this boot's QEMU invocation). The defect is a two-line code fact provable by inspection;untestedmatches the DF-4985/DF-5000 precedent. fix.diff(add the sibling guard) passesgit apply --check; never applied tosys/.
4. Negative results (everything else hunted in ipmi_pci.c and killed)
- iftype dispatch:
ipmi_pci_attachfirst switch (:103-116) fully partitions iface_type (KCS/SMIC proceed, BT/SSIF/unknown β ENXIO); the second switch (:142-153) can only see KCS|SMIC, soerroris always set before use β no uninitialized-errorpath.ipmi2_pci_attachdispatches on progif with explicit default β ENXIO (:205-220); SSIF (progif 0x03) correctly refused. - attach unwind: both
bad:paths (:159-161,:272-274) callipmi_release_resources, which is idempotent-safe here (single call per failure; irq/io pointers only released once).ipmi_kcs_attach(ipmi_kcs.c:481-503) andipmi_smic_attach(ipmi_smic.c:387-400) only set function pointers + one status read β no allocations, nothing to leak.ipmi_attach's two failure modes (bus_setup_intr ipmi.c:847, hook establish :859) fail before creating cdev/kthread β nothing dangling. All early ENXIO returns (:98,112,115,134) precede any resource allocation. Clean. - detach: wired to shared
ipmi_detach(:168,281); it refuses while handles are open (ipmi.c:876-880), destroys cdev, drains kthread, then releases resources β no double-free via this glue. (The early-boot detach-vs-config_intrhook window βipmi_detachnever callsconfig_intrhook_disestablishif the hook hasn't fired β is anipmi.clifetime issue, practically unreachable: the window closes during autoconf before any agent that could trigger a detach exists. Noted here for the nextipmi.cpass; not filed on this file.) - BARs: only BAR(0) mapped;
PCI_BAR_IOtype check (:224) correct; rman does not bounds-check bus_space reads, but SMBIOSoffsetβspacing is properly decoded to {1,2,4} (ipmi_smbios.c:112-118) and native spacing is 1/re-probed β no kernel memory-safety exposure (worst case: stray in-BAR MMIO reads on mis-describing hardware). ipmi_pci_match(:62-70): pure table lookup, terminator-guarded loop.- SMIC native path uses fixed spacing 1 without re-probe (
:229) β matches upstream FreeBSD; no DF divergence.
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_testablenot_testable - requires dual-description BMC hardware (SMBIOS/ACPI/quirk frontend plus a native PCI class-0c:07 function); the audit guest has no such device and QEMU cannot emulate one. fix.diff is git-apply --check verified against the pristine sys/ tree and mirrors the three in-tree sibling guards exactly.
findings/poc/DF-5076/fix.diff (git apply --check passes; never applied to sys/)
Confirmed kernel references
- sys/dev/misc/ipmi/ipmi_pci.c:183-193
- sys/dev/misc/ipmi/ipmi_pci.c:77
- sys/dev/misc/ipmi/ipmi_isa.c:85
- sys/dev/misc/ipmi/ipmi_acpi.c:62
- sys/dev/misc/ipmi/ipmi.c:65
- sys/dev/misc/ipmi/ipmi.c:864
- sys/dev/misc/ipmi/ipmi.c:831
- sys/dev/misc/ipmi/ipmi_pci.c:196-275
- sys/dev/misc/ipmi/ipmi_pci.c:267
- sys/dev/misc/ipmi/ipmi_kcs.c:476
- sys/dev/misc/ipmi/ipmi_smic.c:382
- sys/dev/misc/ipmi/ipmi_smbios.c:112-118
Detail
Evidence (decisive lines)
guard_matrix.log (guard present at ipmi_pci.c:77 / ipmi_isa.c:85 / ipmi_acpi.c:62, absent in ipmi2_pci_probe ipmi_pci.c:183-193); VERDICT.md section 2 (double-attach chain: ipmi_pci.c:267 -> ipmi.c:864/831 -> ipmi_kcs.c:476); env.txt (guest: no class-0c:07 device, no PCI IPMI model in QEMU); fix.diff (git apply --check passes)
PoC changes
evidence pack authored fresh in pass 2 (no seed). No runtime PoC exists or is possible: the defect requires a PCI function with class 0x0c subclass 0x07, which the audit guest's QEMU cannot provide (no PCI IPMI device model upstream).
Verified recommended fix
Add the singleton guard to ipmi2_pci_probe mirroring the siblings: if (ipmi_attached) return (ENXIO); -- see fix.diff (same fix applies to FreeBSD HEAD).
Verdict
Pass-2 audit of the IPMI PCI glue. The driver enforces a singleton invariant via the global ipmi_attached (ipmi.c:65, set to 1 on every successful ipmi_attach at ipmi.c:864), and all three sibling frontend probes honor it -- ipmi_pci_probe (Dell 1028:000d quirk, ipmi_pci.c:77), ipmi_isa_probe (ipmi_isa.c:85), ipmi_acpi_probe (ipmi_acpi.c:62). The native-PCI frontend ipmi2_pci_probe (ipmi_pci.c:183-193) does NOT: it matches any class-0c:07 PCI function regardless of a prior attach. On boards whose BMC is described both by a legacy frontend (SMBIOS/ISA, ACPI, or the Dell quirk) and as a native PCI IPMI function -- the exact topology the sibling guards were added for -- newbus attaches the native function after the first attach: ipmi2_pci_attach (ipmi_pci.c:196-275) maps BAR(0), runs the KCS/SMIC setup, and calls ipmi_attach again (ipmi_pci.c:267), producing a second config hook, a second /dev/ipmiN cdev (ipmi.c:831) and a second kthread (ipmi_kcs.c:476 / ipmi_smic.c:382). When both descriptions point at the same BMC (the historical Dell PE2650 case), two state machines interleave transactions on one KCS/SMIC interface; combined with the driver's known unbounded polling loops (DF-1865/DF-1866/DF-2003) the realistic ceiling is a wedged, CPU-pinning kernel thread -- DoS-class, not memory corruption. FreeBSD HEAD inherits the identical omission (verified against upstream sys/dev/ipmi/ipmi_pci.c), so the fix applies to both projects. Severity Low: hardware-topology-gated (needs dual-description BMC hardware), impact hang/DoS. Untestable on this guest: QEMU has no PCI IPMI device model and the guest exposes no class-0c:07 function (env.txt); the current guest boot does not even attach ipmi. Static proof in guard_matrix.log; fix.diff adds the sibling guard, git apply --check verified, never applied to sys/. Negative results (VERDICT.md section 4): the iftype/progif dispatches fully partition (no uninitialized error path), both bad: unwinds are complete and single-shot (kcs/smic attach allocate nothing; ipmi_attach fails before cdev/kthread creation), detach glue is the shared guarded ipmi_detach, BAR handling has no kernel-memory exposure, and the SMBIOS offset->spacing decode is proper ({1,2,4}, ipmi_smbios.c:112-118). The early-boot detach-vs-config_intrhook window is an ipmi.c lifetime issue (noted for the next ipmi.c pass, practically unreachable).
No comments yet.