β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-5525

iicsmb_intr panics the kernel on any iicbus event outside {INTR_GENERAL..INTR_NOACK} β€” one stray controller status code is a system-down failure

Summary

The event switch's default is panic() over externally-supplied controller event ints (iicbus_if.m imposes no producer bound). Rig-injected event 153 through the real dispatch (the same call pcfintr makes) -> 'panic: iicsmb_intr: unknown event (153)' -> DDB; kprintf+break fix validated (logs and returns, transaction completes, guest alive). Fault-isolation defect, not attacker-data-driven today.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5525 Β· 13 files
FileTypeDescriptionSize
README.md β€” 1.2 KB ↓ raw
VERDICT.md β€” 1.9 KB ↓ raw
df5521_rig.c β€” 7.9 KB view raw
df5521_poc.c β€” 6.8 KB view raw
build.sh β€” 83 B view raw
load_chain.sh β€” 294 B view raw
build.log β€” 5.4 KB view raw
env.txt β€” 980 B view raw
panic.txt β€” 654 B view raw
run.fixed.log β€” 586 B view raw
fix.diff β€” 245 B view raw
manifest.json β€” 624 B view raw
verdict.json β€” 2.9 KB view raw

DF-5525 β€” iicsmb_intr panics the kernel on any iicbus event outside

iicsmb_intr() (sys/bus/iicbus/iicsmb.c:242-243) ends its event switch with panic("%s: unknown event (%d)!", __func__, event). Events are plain ints produced by controller drivers through iicbus_intr() (iiconf.c:45-51, the path every pcf-style ISR takes); any future or third-party controller that reports a status code outside INTR_GENERAL..INTR_NOACK (0x1..0x7) takes the whole system down instead of being logged and dropped.

Files

df5521_rig.c shared rig; hw.dfa.fire_event=N injects iicbus_intr(iicbus0, N, &c) exactly like a controller ISR (only while the bus owner is set, i.e. mid-transaction) df5521_poc.c fireevent mode: child holds SMB_BREAD in flight while the parent fires event 153 (0x99) panic.txt baseline: panic: iicsmb_intr: unknown event (153)! with the full backtrace through iicbus_intr -> sys___sysctl run.fixed.log patched: kprintf + continue, guest alive fix.diff panic -> kprintf+break

Reproduce

chain up (load_chain.sh); sysctl hw.dfa.rdelay=300; /root/df5521_poc fireevent # baseline: panic -> db> (serial console)

VERDICT.md
↓ download raw

DF-5525 VERDICT β€” REPRODUCED (kernel panic from a controller-supplied event value; hardening fix validated)

The bug

iicsmb_intr() handles INTR_GENERAL/START/STOP/RECEIVE/TRANSMIT/NOACK/ ERROR and then (sys/bus/iicbus/iicsmb.c:242-243):

default:
    panic("%s: unknown event (%d)!", __func__, event);

The event is an unvalidated int produced by whatever controller driver sits under the iicbus and is delivered through the production interrupt path (iicbus_intr() β†’ IICBUS_INTR(sc->owner), iiconf.c:45-51). iicbus_if.m defines no contract that pins producers to {1..7}; a controller bug (or a new event added to one driver but not the bridge β€” exactly how INTR_NOACK-style additions happen) turns one stray status code into a full system panic. Fault isolation, not attacker-reachable data: severity Info.

Verification

Baseline (stock modules, production chain up, owner held by an in-flight SMB_BREAD): firing iicbus_intr(iicbus0, 153, &c) β€” the same call pcfintr makes on 8 paths β€” produced:

panic: iicsmb_intr: unknown event (153)!
iicsmb_intr() at iicsmb_intr+0x67
dfa_fire_event_sysctl() at ...
sysctl_root ... userland_sysctl ... sys___sysctl
Debugger("panic")  β†’ db>

Fixed (panic β†’ kprintf + break): iicsmb_intr: unknown event (153)! is logged, iicbus_intr returned (no fault), the in-flight transaction completes, /dev/smb0 remains, guest alive.

Fix

fix.diff: log-and-continue. (An upstream-grade alternative is KASSERT under DEBUG discipline; the kprintf preserves diagnosability without the system-down failure mode.)

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

fixed
baseline reproduced→ patch + rebuild →patched clean

Stock: 1/1 runs panic (iicsmb_intr: unknown event (153)!, DDB). Patched: 1/1 clean -- event logged, iicbus_intr returns, in-flight transaction completes, /dev/smb0 intact, guest alive. Validated as part of the combined fixed-module build shared with DF-5521/5522/5523.

panic.txt vs run.fixed.log; fix.diff
↓ fix.diffper-fix-DF-5525

Confirmed kernel references

Detail

Evidence (decisive lines)

panic.txt (decisive: panic string + full backtrace through the production iicbus_intr dispatch with sc->owner set); run.fixed.log (kprintf instead of panic, guest alive, /dev/smb0 intact); fix.diff

PoC changes

shared rig with DF-5521; hw.dfa.fire_event sysctl injects iicbus_intr() on the rig's iicbus child exactly as a controller ISR would

Verified recommended fix

Replace the panic in the default case with a kprintf + break (or KASSERT under a debug option). See fix.diff (validated live).

Verdict

REPRODUCED: iicsmb_intr's default case panics on any iicbus event outside {1..7} (iicsmb.c:242-243). The event int is produced by the controller driver under the bus and delivered through the production interrupt path (iicbus_intr -> IICBUS_INTR(sc->owner), iiconf.c:45-51) with no interface-level contract bounding it (iicbus_if.m). Injecting event 153 the way a controller ISR would (same call pcf's pcfintr makes on 8 paths) with the owner held by an in-flight SMB_BREAD: 'panic: iicsmb_intr: unknown event (153)!' with backtrace iicsmb_intr+0x67 <- dfa_fire_event_sysctl <- sysctl_root <- userland_sysctl <- sys___sysctl -> DDB. With the fix (kprintf + break): 'iicsmb_intr: unknown event (153)!' logged, iicbus_intr returns, transaction completes, guest alive. Fault-isolation/robustness defect reachable only via controller-driver code (not attacker data) => severity Info.