DF-5633 / verdict.json
{ "finding_id": "DF-5633", "status": "reproduced", "verdict": "REPRODUCED on stock iicbus.ko: iicbus_attach (iicbus.c:144-146) re-creates the ic/iic/iicsmb trio unguarded on every attach, while neither iicbus_detach nor devclass_delete_driver ever deletes the FIXEDCLASS children -- each detach+re-attach cycle of an iicbus with a resident bridge leaks 3 struct bsd_device (M_BUS) and mints duplicate devclass units; with iic.ko attachable this produces duplicate /dev/iicN character devices on ONE physical bus (independent sc_addr state, further breaking iicbus_transfer_gens nkid!=1 check). 2 cycles: nchildren 3->9; /dev/iic0 -> /dev/iic0..3. fix.diff guards the trio with device_find_child (as iic_identify already does); fixed module: nchildren constant across cycles.", "reproduced": true, "impact": "dos", "confidence": "certain", "exploit_chain": "root: detach+re-attach iicbus0 (kldunload/kldload iicbus.ko with a kernel-resident bridge, out-of-tree bridge without MODULE_DEPEND, or rescan/rebind) -> each cycle: device_detach(iicbus0) leaves children alive -> device_probe_and_attach -> iicbus_attach mints a fresh trio -> unbounded M_BUS leak + duplicate iicN/iicsmbN units -> duplicate /dev/iicN nodes with divergent sc_addr on one wire.", "evidence": "run_a2_dmesg.txt (stock: STAT: nchildren=3 -> CYCLE-done: nchildren=9 after 2 production device_detach/device_probe_and_attach cycles, ic/iic/iicsmb units 0,1,2; softc address changes between STATs proving detach freed it while children persisted); run_b_5559.log (/dev/iic0 -> /dev/iic0 /dev/iic1 -> /dev/iic0..3 on one iicbus0); run_d_fixed_dmesg.txt (fixed: CYCLE-done: nchildren=5 stable across cycles)", "kernel_refs": [ "sys/bus/iicbus/iicbus.c:144-146", "sys/bus/iicbus/iicbus.c:156-162", "sys/kern/subr_bus.c:853-899", "sys/bus/iicbus/iiconf.c:365" ], "poc_changes": "Rig lives in ../DF-5632/ (df5632_rig.c): /dev/df5632 ioctl CYCLE drives production device_detach()+device_probe_and_attach() on iicbus0; duplicate-node demonstration uses iicbus.ko rebuilt with DF-5559s validated fix so production iic.ko can attach.", "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": 900, "guest_dirty": 0, "build_cmd": "sh /root/df5632/build.sh (see ../DF-5632 pack; mod_5559 variant enables iic.ko attach)", "run_cmd": "sh /root/df5632/run_a_stock.sh (stock leak witness); sh /root/df5632/run_b_5559.sh (duplicate /dev/iicN witness); sh /root/df5632/run_d_fixed.sh (fixed: no growth)", "code_hash": "df5632_rig.c 89e5ff9630fa73906f5e0fb4b882e484dcc0014050cbfc65bc61801f8796bc03 (shared rig, ../DF-5632)", "notes": "In-tree masking: MODULE_DEPEND(iicbb, iicbus) fences the pure-module kldunload path while iicbb.ko is loaded; the leak needs a resident bridge (kernel-config device iicbb, out-of-tree bridge, or rescan flows). The 2026-10-06 task_log lead from the pcf pass (iicbus wildcard children do not attach ... kldunload iicbus succeeds while iicbus0 attached) is root-caused here plus DF-5559.", "recommended_fix": "Guard the trio in iicbus_attach with device_find_child(dev, \"ic\"/\"iic\"/\"iicsmb\", -1) == NULL before each creation (mirroring iic_identifys own guard), routing through the fixed bus_add_child so ivars are allocated (fix.diff).", "fix_status": "fixed", "fix_baseline_reproduced": true, "fix_patched_reproduced": false, "fix_verdict": "With iicbus.ko rebuilt from fix.diff, 2 detach/re-attach cycles leave nchildren constant (5 incl. two rig-added children; the trio does not duplicate) and unload is clean; baseline growth 3->9 eliminated.", "fix_evidence": "run_d_fixed_dmesg.txt (CYCLE-done: nchildren=5 before and after cycles; RUN-D-DONE; no trap)" } |