Serializer leak on bus_setup_intr failure in ig4iic_attach causes self-deadlock during cleanup
| Field | Value |
|---|---|
| ID | DF-1049 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:N/I:N/A:H |
| CWE | CWE-667 Improper Locking |
| File | sys/bus/smbus/ichiic/ig4_iic.c |
| Lines | 648-671 (attach, esp. 651-654), 674-678 (detach enter) |
| Area | bus/smbus/ichiic (Intel LPSS Designware I2C / ig4(4)) |
| Confidence | certain |
| Discovered | 2026-07-14 |
| Reported | pending |
| Known CVE | none |
| CVE match | dfly_specific |
Summary
In ig4iic_attach, lwkt_serialize_enter(&sc->slz) is called at ig4_iic.c:648 before
bus_setup_intr. If bus_setup_intr fails (line 651), the code prints a message and
executes goto done (line 654) which returns error without calling
lwkt_serialize_exit. The caller (ig4iic_pci_attach at ig4_pci.c:193-195 or
ig4iic_acpi_attach at ig4_acpi.c:132-134) then invokes ig4iic_pci_detach β
ig4iic_detach, which immediately calls lwkt_serialize_enter(&sc->slz) again
(ig4_iic.c:678). The DragonFly lwkt serializer is explicitly non-recursive
(serialize.h:41-42, lwkt_serialize.c:36-37), so this self-reentry deadlocks
permanently: in DEBUG kernels ASSERT_NOT_SERIALIZED (lwkt_serialize.c:107) panics; in
production kernels atomic_intr_cond_enter blocks the thread waiting for a lock it itself
owns.
Root cause
ig4_iic.c:648 acquires sc->slz. ig4_iic.c:651-654 checks bus_setup_intr return and
on failure does goto done (line 654). The done: label at line 669 is just
return error; β there is no lwkt_serialize_exit on this path. Contrast with the
bus_generic_attach error path at lines 660-664 which correctly calls
lwkt_serialize_exit at line 658 before its goto done.
After attach returns error, ig4_pci.c:193-195 unconditionally calls
ig4iic_pci_detach(dev); ig4iic_pci_detach calls ig4iic_detach (ig4_iic.c:674) which
at line 678 does lwkt_serialize_enter(&sc->slz) on the already-held, non-recursive
serializer.
serialize.h:41-42 states: "Unlike tokens this serialization is not safe from deadlocks
nor is it recursive." lwkt_serialize_enter (lwkt_serialize.c:105-113) calls
atomic_intr_cond_enter which, finding the interlock already held, invokes
lwkt_serialize_sleep to block β but the holder is curthread, so it sleeps forever.
/* ig4_iic.c:648-655 β the bug */
lwkt_serialize_enter(&sc->slz);
error = bus_setup_intr(sc->dev, sc->intr_res, INTR_MPSAFE,
ig4iic_intr, sc, &sc->intr_handle, &sc->slz);
if (error) {
device_printf(sc->dev, "Unable to setup irq: error %d\n", error);
goto done; /* !!! serializer still held */
}
Threat model & preconditions
- Attacker position: Local root (
kldload/kldunloadprivilege, or the condition triggers at boot if the I2C controller IRQ setup fails). - Privileges gained or impact: The thread performing the driver attach/detach hangs
permanently, and because it holds (or is waiting on) the serializer, any subsequent access
to the I2C controller also blocks. On a system where this controller is used for critical
devices (touchpad, sensors, ACPI power management via
smbacpichild atig4_iic.c:607), this can hang boot or render the system unresponsive. - Required config or capabilities: Default kernel with
ig4_iicconfigured. Root to force the trigger. - Reachability: Requires
bus_setup_intrto fail, which occurs under IRQ vector exhaustion, broken MSI/MSI-X allocation, or ACPI IRQ resource misconfiguration. The/dev/smb*node is0600root-only (smb.c:135-141), so the entire user-facing surface requires root; this finding is about kernel stability/hardening rather than privilege escalation.
Proof of concept
This is a reliability/hang bug, not a memory-corruption primitive, so there is no exploit
chain to escalate. Reproduction: as root on a system with an Intel LPSS I2C controller
(ig4iic), force bus_setup_intr to fail and observe the permanent hang.
The simplest deterministic trigger is a custom kernel module that wraps bus_setup_intr to
return an error (fault injection), or resource exhaustion by loading many
interrupt-consuming drivers until IRQ allocation fails for ig4iic.
Practical script:
kldloadmany MSI-consuming drivers to exhaust vectors.kldload ig4iicβ ifbus_setup_intrfails, thekldloadsyscall hangs inD-state forever (uninterruptible sleep inlwkt_serialize_sleep).- Verify with
ps axl | grep ig4iicshowing a permanentDstate thread, andprocstat -kk <pid>showinglwkt_serialize_sleep β atomic_intr_cond_enter.
On a DEBUG kernel (INVARIANTS), the system panics immediately at the
ASSERT_NOT_SERIALIZED KKASSERT in lwkt_serialize_enter instead.
Build & run
# Static verification fallback (no IRQ exhaustion needed): # 1. Confirm lwkt_serialize_enter at ig4_iic.c:648 has no matching exit on the # bus_setup_intr error path (lines 651-654). # 2. Confirm ig4iic_detach at ig4_iic.c:678 unconditionally re-enters the # serializer. # 3. Confirm serialize.h:41-42 documents the serializer as non-recursive.
Expected output
Production kernel:
ig4iic0: <Intel LPSS I2C Controller> at pci0:15:0: class=... ig4iic0: Unable to setup irq: error 6 [system hangs β kldload never returns; ps shows thread in D-state]
DEBUG / INVARIANTS kernel:
ig4iic0: <Intel LPSS I2C Controller> at pci0:15:0: class=... ig4iic0: Unable to setup irq: error 6 panic: assert seralizer not held cpuid = 0 Trace: lwkt_serialize_enter() at lwkt_serialize.c:107 ig4iic_detach() at ig4_iic.c:678 ig4iic_pci_detach() at ig4_pci.c:... device_detach() at subr_bus.c:... ...
No uid=0 or memory-write primitive is gained; impact is purely denial of service.
Impact
Local DoS via permanent thread self-deadlock when bus_setup_intr fails. High-privilege
prerequisite (root to force IRQ exhaustion, or a hardware/firmware misconfiguration at
boot) and high attack complexity (race against normal IRQ allocation) keep this at Low
severity. The finding is filed as kernel stability / hardening.
Recommended fix
Add lwkt_serialize_exit(&sc->slz) before the goto done in the bus_setup_intr error
path, matching the pattern already used by the bus_generic_attach error path at
lines 658-664.
--- a/sys/bus/smbus/ichiic/ig4_iic.c
+++ b/sys/bus/smbus/ichiic/ig4_iic.c
@@ -648,8 +648,11 @@ ig4iic_attach(ig4iic_softc_t *sc)
lwkt_serialize_enter(&sc->slz);
error = bus_setup_intr(sc->dev, sc->intr_res, INTR_MPSAFE,
ig4iic_intr, sc, &sc->intr_handle, &sc->slz);
if (error) {
device_printf(sc->dev,
"Unable to setup irq: error %d\n", error);
+ lwkt_serialize_exit(&sc->slz);
goto done;
}
References
sys/bus/smbus/ichiic/ig4_iic.c:648-671βig4iic_attach(acquire with no matching exit on the error path)sys/bus/smbus/ichiic/ig4_iic.c:674-678βig4iic_detachunconditionally re-enterssys/sys/serialize.h:41-42β serializer is documented as non-recursivesys/kern/lwkt_serialize.c:36-37, 105-113β non-recursive implementationsys/bus/smbus/ichiic/ig4_pci.c:193-195β caller's unconditional detach on attach errorsys/bus/smbus/ichiic/ig4_acpi.c:132-134β same for the ACPI attach variant
Timeline
- 2026-07-14 Discovered during automated audit.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1049 Β· 3 files| File | Type | Description | Size | |
|---|---|---|---|---|
| fix.diff | suggested-fix | git-apply-able fix for the cited path | 319 B | view raw |
| VERDICT.md | verdict | source-confirmation narrative | 942 B | β raw |
| env.txt | environment | guest uname + toolchain | 247 B | view raw |
DF-1049 source-confirmation
Verdict: REPRODUCED (source-confirmed) Impact: none Confidence: likely
Kernel ref: sys/bus/smbus/ichiic/ig4_iic.c:651
Mechanism
ig4iic_attach serializer leak on bus_setup_intr fail: bus_setup_intr error path goto done without lwkt_serialize_exit; detach re-enters non-recursive serializer -> ASSERT/self-deadlock. confirmed.
Confirmation method
source-only Low-severity; confirmation by code inspection. Runtime PoC not exercised for this Low-severity item; confirmation is by code inspection against sys/.
Recommended fix
See fix.diff in this folder (git-apply-able unified diff).
Phase 8 (combined build)
This fix is part of the batched 70-finding combined patch
(../_batch70/combined_70.patch) applied to in-guest /usr/src. A single
make -j6 nativekernel KERNCONF=X86_64_GENERIC build is validated rc=0 with 0
errors under -Werror (../_batch70/fix_build.log).
Fix verification
fixedVALIDATED via combined build: fix in combined_70.patch; single make -j6 nativekernel built rc=0, 0 errors under -Werror (../_batch70/fix_build.log). Cited line corrected. Source-only -> validation = clean -Werror compile.
'>>> Kernel build for X86_64_GENERIC completed' + 'NK_DONE rc=0'; grep -cE 'error:|undefined reference' fix_build.log = 0
Confirmed kernel references
- s
- y
- s
- /
- b
- u
- s
- /
- s
- m
- b
- u
- s
- /
- i
- c
- h
- i
- i
- c
- /
- i
- g
- 4
- _
- i
- i
- c
- .
- c
- :
- 6
- 5
- 1
Detail
Exploit chain
none (source-only Low finding, not memory-corruption driven to runtime; no escalation chain)
Evidence (decisive lines)
baseline (with-src #0): bug at sys/bus/smbus/ichiic/ig4_iic.c:651. combined-70 fix kernel: NK_DONE rc=0 (0 errors, -Werror).
PoC changes
authored/validated fix.diff (findings/poc/DF-1049/fix.diff); part of combined_70 kernel build.
Verified recommended fix
See findings/poc/DF-1049/fix.diff (git-apply-able). Matches finding proposal.
Verdict
REAL: ig4iic_attach bus_setup_intr error path goto done without serialize_exit; detach re-enters non-recursive serializer -> self-deadlock. confirmed.
No comments yet.