DF-5635 / verdict.json
{ "finding_id": "DF-5635", "status": "reproduced", "verdict": "REPRODUCED on stock iicbus.ko: iicbus_detach (iicbus.c:156-162) discards bus_generic_detach()s error and returns 0 unconditionally, so a child that refuses to detach (EBUSY -- in-tree producer: DF-5521-guarded iicsmb) leaves iicbus0 marked detached + driverless with its softc kfreed (device_set_driver(NULL)) while the child remains DS_ATTACHED; the childs next iicbus_request_bus derefs device_get_softc(bus)==NULL at iiconf.c:88/:101 -- Fatal trap 12, fault VA 0x8 (= offsetof(struct iicbus_softc, owner)), Stopped at iicbus_request_bus+0x89. Also answers the DF-5563 lead: yes, iiconfs drain/dying protocol requires the wake/drain from THIS detach, which DF-5563s validated fix already adds (not re-reported). fix.diff propagates the error; fixed: device_detach returns EBUSY, bus stays attached and servicable.", "reproduced": true, "impact": "panic", "confidence": "certain", "exploit_chain": "root: attach an iicbus client child that can refuse detach (rig df5632k0; in-tree: iicsmb while bridge-owned per DF-5521) -> force bus driver removal (kldunload path / devclass_delete_driver / device_detach) -> iicbus_detach swallows the childs EBUSY -> newbus completes teardown: softc freed, driverless, state DS_NOTPRESENT, child still attached -> any subsequent iicbus_request_bus(child) reads sc->owner at NULL+8 -> kernel page fault, panic.", "evidence": "panic_5635_stock.txt (df5632k0 detach: REFUSING (EBUSY), iicbus0: detached, device_detach(iicbus0) returned 0, driver=(NONE-DRIVERLESS) state=0 softc=0 with child[3] ... driver=df5632k state=3, then Fatal trap 12, fault virtual address = 0x8, Stopped at iicbus_request_bus+0x89: movq 0x8(%r12),%rax); run_d_fixed.log (DETACH_BUS: device_detach(iicbus0) returned 16, bus stays driver=iicbus state=3 softc=0xfffff8008d581130, REQBUS: returned 0)", "kernel_refs": [ "sys/bus/iicbus/iicbus.c:156-162", "sys/bus/iicbus/iiconf.c:88", "sys/bus/iicbus/iiconf.c:101", "sys/kern/subr_bus.c:device_detach", "sys/kern/subr_bus.c:device_set_driver", "sys/bus/iicbus/iicsmb.c:155-171" ], "poc_changes": "Rig lives in ../DF-5632/ (df5632_rig.c): df5632k child driver whose detach returns EBUSY under hw.df5632.childbusy=1; /dev/df5632 ioctls drive production device_detach(iicbus0) and iicbus_request_bus().", "attempts": 2, "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": 700, "guest_dirty": 0, "build_cmd": "sh /root/df5632/build.sh (see ../DF-5632 pack)", "run_cmd": "sh /root/df5632/run_c_panic.sh (stock: ./dfctl failchild; sysctl hw.df5632.childbusy=1; ./dfctl detach_bus; ./dfctl reqbus -> Fatal trap 12); sh /root/df5632/run_d_fixed.sh (fixed: EBUSY propagated, no panic)", "code_hash": "df5632_rig.c 89e5ff9630fa73906f5e0fb4b882e484dcc0014050cbfc65bc61801f8796bc03 (shared rig, ../DF-5632)", "notes": "The panic primitive is a NULL-base read (sc->owner) -- deterministic panic, not a controllable read. Reachability needs a child whose detach fails; in-tree iicsmb (DF-5521 guard) is the natural producer, and module dependencies fence the pure-kldunload route while client modules are loaded -- root-gated, Low per family rubric. The wake/drain half of the detach gap is DF-5563s (its validated fix.diff already patches iicbus_detach); this finding covers the swallowed child error, an independent defect at the same lines.", "recommended_fix": "Propagate the failure: error = bus_generic_detach(dev); if (error) return error; (plus propagate iicbus_resets error) -- see fix.diff; composes trivially with DF-5563s drain block at the head of the same function.", "fix_status": "fixed", "fix_baseline_reproduced": true, "fix_patched_reproduced": false, "fix_verdict": "With iicbus.ko rebuilt from fix.diff, the same busy-child scenario returns EBUSY (16) from device_detach(iicbus0); the bus remains attached (driver=iicbus state=3, softc non-NULL), the child stays attached, and iicbus_request_bus on the attached bus succeeds (rc=0, clean release). The inconsistent-state NULL-softc panic path is eliminated.", "fix_evidence": "run_d_fixed.log (dfctl detach_bus: kernel rc=16, dfctl reqbus: kernel rc=0); run_d_fixed_dmesg.txt (DETACH_BUS: device_detach(iicbus0) returned 16, driver=iicbus state=3 softc=0xfffff8008d581130, RUN-D-DONE)" } |