⬢ DragonFlyBSD Kernel Audit
DF-5490 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5490",
  "status": "reproduced",
  "reproduced": true,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "REPRODUCED: no DRIVER_MODULE(iicbus, pcf, ...) exists (only iicbus.c:194 on iicbb; cf. the bridge-enumeration pattern iicbb.c:441-445 and DRIVER_MODULE(smbus, ichsmb) ichsmb.c:696), so the iicbus child added at pcf.c:200 never attaches -- device_probe_child (subr_bus.c:1414-1484) only probes drivers registered on the parent (pcf) bus. Live proof on the QEMU guest with pcf0 attached via the isahint production API path: child dumped as iicbus0 state=0 softc=0 (DS_NOTPRESENT, NULL softc), and the exact pcfintr sink call iicbus_intr(pcf->iicbus, INTR_RECEIVE, &data) (pcf.c:475, one of 8 pcfintr call sites) page-faults reading sc->owner (offset 8) of the NULL softc: Fatal trap 12, fault virtual address = 0x8, Stopped at iicbus_intr+0x18: movq 0x8(%rax),%rbx -> kernel panic, DDB (1/1 runs). On real PCF8584 silicon in default interrupt mode pcfintr is the registered handler (interrupt uses mplock: pcf0) and ENI is permanently enabled since probe (pcf.c:171->537, also pcf.c:300/490), so the FIRST chip interrupt after attach panics deterministically; only the IRQ delivery was substituted by the rig because QEMU has no PCF8584 model. Driver is also functionally dead (no /dev/iicN; pcf_write/pcf_read have no in-tree caller). FIX VALIDATED live: fix.diff adds DRIVER_MODULE(iicbus, pcf, ...) + a pcfintr NULL-guard; patched pcf.ko -> iicbus0: <Philips I2C bus> on pcf0 addr 0xaa, child state=3 softc=0xfffff8004f0e7478, sink call RETURNED (no fault), guest alive (1/1). Hardware-gated trigger => severity Low.",
  "exploit_chain": "PCF8584 hardware at a hinted ISA port + default interrupt mode: boot/kldload attaches pcf0 and registers pcfintr for the ISA IRQ; ENI has been enabled since probe (pcf.c:171->pcf_rst_card:537); any completed byte transfer (master or slave event) clears PIN and asserts INT; pcfintr runs, status has PIN clear, slave-receiver branch reaches iicbus_intr(pcf->iicbus, INTR_RECEIVE, &data) at pcf.c:475 -> iiconf.c:47-50 device_get_softc(child)==NULL -> sc->owner read at NULL+8 -> Fatal trap 12 -> panic. Every interrupt-bearing pcf deployment panics on first bus event; no attacker privilege needed beyond owning the hardware/bus.",
  "evidence": "panic.txt (decisive: child[0]=iicbus0 state=0 softc=0 then Fatal trap 12 ... fault virtual address = 0x8 ... Stopped at iicbus_intr+0x18: movq 0x8(%rax),%rbx); run.log.baseline_panic_full (full untrimmed serial console of the baseline run incl. attach lines); run.fixed_serial.log (patched run: iicbus0 attaches, RETURNED (no fault)); fix.diff; df5490_rig.c (production-API attach rig + sink)",
  "kernel_refs": [
    "sys/bus/iicbus/pcf/pcf.c:200",
    "sys/bus/iicbus/pcf/pcf.c:193",
    "sys/bus/iicbus/pcf/pcf.c:412",
    "sys/bus/iicbus/pcf/pcf.c:475",
    "sys/bus/iicbus/pcf/pcf.c:537",
    "sys/bus/iicbus/pcf/pcf.c:300",
    "sys/bus/iicbus/pcf/pcf.c:643",
    "sys/bus/iicbus/iicbus.c:194",
    "sys/bus/iicbus/iiconf.c:45",
    "sys/bus/iicbus/iiconf.c:50",
    "sys/kern/subr_bus.c:1414",
    "sys/bus/iicbus/iicbb.c:441",
    "sys/bus/smbus/ichsmb/ichsmb.c:696",
    "sys/bus/isa/isahint.c:53"
  ],
  "poc_changes": "no seed PoC existed (pass-2 discovery); wrote df5490_rig.c from scratch: isahint-style BUS_ADD_CHILD/bus_set_resource/device_probe_and_attach attach (kenv hints unusable: resource_query_string enumerates only the compiled devtab, subr_bus.c:2401), then state dump + exact pcfintr sink. Rig v1 passed cpuid=-1 for the IRQ resource and hit an unrelated nexus KASSERT; fixed by passing machintr_legacy_intr_cpuid(irq) exactly as isahint.c:70-72 does.",
  "attempts": 4,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026     root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64",
  "runtime_sec": 5400,
  "guest_dirty": 0,
  "build_cmd": "guest: make in /usr/src/sys/bus/iicbus/df5490 (rig KLD) and /usr/src/sys/bus/iicbus/pcf (fixed module after patch -p1 < fix.diff); all -Werror clean",
  "run_cmd": "vm.sh run_root kldload iicbus && kldload pcf && kldload /root/df5490_rig.ko  # baseline: panic; fixed: kldload pcf_fixed.ko first, then rig -> no fault",
  "code_hash": "2c8768eaa26fc61dcee4317f5b7413b32b995f77c9e08c9fcd66edeaae36b1d5",
  "notes": "Cross-observations for other files (not pcf.c): (1) even with the fix, iicbus0s wildcard children (ic/iic/iicsmb) did not attach and /dev/iic0 did not appear -- iicbus.c/iic.c child-handling question for a future audit; (2) kldunload iicbus succeeded while iicbus0 was attached (bus-driver unload not pinned to attached children); (3) DF loader does not parse /boot/device.hints. Guest reset with-src after testing.",
  "recommended_fix": "Add #include \"../iicbus.h\" and DRIVER_MODULE(iicbus, pcf, iicbus_driver, iicbus_devclass, NULL, NULL); to pcf.c (mirror ichsmb.c:696), plus an early if (pcf->iicbus == NULL || device_get_softc(pcf->iicbus) == NULL) return; guard in pcfintr() -- see fix.diff (validated live).",
  "fix_status": "fixed",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": false,
  "fix_verdict": "Baseline stock pcf.ko: 1/1 rig runs panic (Fatal trap 12, VA 0x8, iicbus_intr+0x18). Patched pcf.ko (fix.diff applied to guest /usr/src, module rebuilt, same rig): 1/1 clean -- iicbus0 attaches (on pcf0 addr 0xaa), child softc valid, iicbus_intr returns without fault, guest stays up.",
  "fix_evidence": "run.fixed_serial.log; run.log.baseline_panic_full (before/after); fix.diff"
}