iic_attach() never initializes sc->sc_dev β every iicread()/iicwrite()/iicioctl() dereferences NULL and panics the kernel
Summary
sc->sc_dev is never assigned anywhere (the DFly port dropped FreeBSD's line) and the zero-alloc softc makes it NULL forever: read/write/ioctl all begin device_get_parent(sc->sc_dev) -> the FIRST syscall on any /dev/iicN unconditionally page-faults (movq 0x28(%rdi) with rdi==NULL). Reproduced: first I2CRDWR -> Fatal trap 12 fault VA 0x28. Together with DF-5559 this makes iic(4) dead-on-arrival on DragonFly - one-syscall local DoS for whoever can open the node, no escalation. sc->sc_dev=dev fix validated (zero panics across hundreds of ioctls, device functional).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5560 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| trigger.c | β | 8.0 KB | view raw | |
| panic.txt | β | 3.9 KB | view raw | |
| fix.diff | β | 366 B | view raw | |
| env.txt | β | 541 B | view raw | |
| verdict.json | β | 4.1 KB | view raw |
Fix verification
fixedfix.diff applied to the guest's /usr/src copy of sys/bus/iicbus/iic.c; only iic.ko rebuilt and reloaded. Baseline stock: first ioctl on /dev/iic0 panics the kernel (Fatal trap 12, fault 0x28, stopped in device_get_parent). Patched: zero panics; the same PoC plus the full DF-5558 suite (hundreds of ioctls incl. failing transfers) runs to completion with correct results.
fix.diff; ../DF-5558/fix_build.log (iic.ko rebuild); ../DF-5558/run.log + fix_run.log (post-fix functionality); panic.txt (baseline).
Confirmed kernel references
Detail
Evidence (decisive lines)
panic.txt (full trap: fault va 0x28, current process 2071 rdwrleak, 'Stopped at device_get_parent: movq 0x28(%rdi),%rax', db> prompt, CPUs stopped); trigger.c (open + first ioctl); ../DF-5559/stock-probe-evidence.log (same panic captured in the stock-probe session); ../DF-5558/run2-full.log + run.log + fix_run.log (post-fix device fully functional, zero panics).
PoC changes
No seed PoC (found during the DF-5558 verification run when the first ioctl on the freshly-attached stock /dev/iic0 panicked instead of reaching I2CRDWR). trigger.c is the pre-fix-tweak copy of the DF-5558 PoC; the panic is the baseline observation, requiring no code beyond open()+ioctl().
Verified recommended fix
Assign sc->sc_dev = dev in iic_attach() before make_dev (see fix.diff) -- restores the FreeBSD original's initialization.
Verdict
REPRODUCED as a deterministic kernel panic. iic_attach() (sys/bus/iicbus/iic.c:123-138) never assigns sc->sc_dev (declared :50); the zero-allocated softc leaves it NULL forever, and iicwrite (:197), iicread (:237) and iicioctl (:288) each do device_get_parent(sc->sc_dev) on entry -- movq 0x28(%rdi),%rax with %rdi==NULL -- so the FIRST read(2)/write(2)/ioctl(2) on any /dev/iicN faults the kernel. The FreeBSD original assigns sc->sc_dev = dev; the DragonFly port dropped it. Live proof on the guest with stock iic.ko (/dev/iic0 instantiated via the DF-5539 harness + the DF-5559 setup fix in iicbus.ko, which does not touch iic.c): open() succeeds, first I2CRDWR ioctl panics -- 'Fatal trap 12 ... fault virtual address = 0x28 ... Stopped at device_get_parent: movq 0x28(%rdi),%rax', current process = the PoC (panic.txt). fix.diff (sc->sc_dev = dev;) validated by rebuilding only iic.ko: zero panics across the full DF-5558 suite (hundreds of ioctls), device fully functional (success reads return the emulated TX pattern, failures return IIC_ENOACK). Impact: unconditional local DoS for anyone who can open the node; 0600 root:wheel on default config (and the DF-5559 attach bug usually prevents the node from existing at all -- the two bugs together explain why iic(4) has been dead-on-arrival on DragonFly and none of the iic.c ioctl bugs ever surfaced in the field). No escalation: fixed-offset NULL read, no controllable write.
No comments yet.