DF-5559 / verdict.json
{ "finding_id": "DF-5559", "status": "reproduced", "reproduced": true, "impact": "none", "confidence": "certain", "verdict": "REPRODUCED (as an uninitialized-value use with deterministic stock effect). iic_probe() (sys/bus/iicbus/iic.c:115) gates /dev/iicN creation on iicbus_get_addr(), a __BUS_ACCESSOR-generated inline (iicbus.h:56 via sys/sys/bus.h:542-557) that discards BUS_READ_IVARs error and returns its never-written local v. No driver in the iicbus ancestry implements bus_read_ivar and ivars are never allocated (iicbus.c:59-73, 144-146, 164-171); the no-DEFAULT method resolution lands on kobj_error_method (makeobjops.awk:281-282, subr_kobj.c:69-72) which returns ENXIO without touching *result. Stock-kernel proof on the guest: (1) df5558.readivar -- BUS_READ_IVAR error=6 (ENXIO) with sentinel 0x77777777 UNTOUCHED; (2) with stock iicbus.ko+iic.ko the iic child exists but /dev/iic0 is never created -- 240+ device_probe_and_attach re-probes (incl. from zero-sprayed stacks) all ENXIO, because the probe contexts kobj_init/kmalloc path rewrites the slot with garbage > 0 right before DEVICE_PROBE, while the sysctl context returns 0x00000000 -- the value is context-dependent stack residue; (3) the task_log lead is corrected: DragonFlys accessor does NOT deref device_get_ivars, so there is no NULL-deref panic -- the defect is the discarded-failure uninit return. Net stock effect: the production iic(4) interface is dead-on-arrival (also explaining why the pass-1 I2CRDWR findings were never seen in the wild). fix.diff (bus_read_ivar/bus_write_ivar on the iicbus driver, answering 0 for the unallocated addr ivar) validated by rebuilding only iicbus.ko: BUS_READ_IVAR error=0 v=0x0 (written), production iic.ko attaches on the first kldload, /dev/iic0 appears. Direct security impact is contained in-kernel (value is only compared); severity Low.", "exploit_chain": "", "evidence": "stock-probe-evidence.log (serial console: 240+ attachiic try N: device_probe_and_attach error=6 on stock + the readivar ENXIO/untouched line); dmesg.txt (fixed state: readivar: BUS_READ_IVAR error=0 v=0x0 (written), iic0 attaches); ../DF-5558/run2-full.log (iic0: <I2C generic I/O> on iicbus0 + /dev/iic0 with only iicbus.ko fixed); groom5558.c (proof tool: df5558.readivar / df5558.getaddr_spray / df5558.attachiic).", "kernel_refs": [ "sys/bus/iicbus/iic.c:115", "sys/bus/iicbus/iicbus.h:56", "sys/bus/iicbus/iicbus.h:44-47", "sys/bus/iicbus/iicbus.c:59-73", "sys/bus/iicbus/iicbus.c:144-146", "sys/bus/iicbus/iicbus.c:164-171", "sys/sys/bus.h:542-557", "sys/kern/bus_if.m:82-87", "sys/tools/makeobjops.awk:281-282", "sys/kern/subr_kobj.c:69-72" ], "poc_changes": "No seed PoC (pass-2 finding verified in the same run). Proof tool is groom5558.ko (sysctl df5558.readivar with a 0x77777777 sentinel; df5558.getaddr_spray two-function stack spray; df5558.attachiic controlled re-probe). The stack-pattern spray did not hit the accessors exact slot (stable zeroed spill in the sysctl context) -- recorded honestly; the ENXIO/untouched dispatch proof plus the stock-vs-fixed probe behavior carry the result.", "attempts": 3, "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": 1800, "guest_dirty": 0, "build_cmd": "cd /root/df5558 && sh build.sh (builds groom5558.ko with the harness)", "run_cmd": "kldload stack per ../DF-5558/run.sh; sysctl df5558.readivar=1; sysctl df5558.attachiic=1", "code_hash": "1ba5e7d988c3b6c51fdf0431ad8c316602eb0d42a42af9423d9dc218fcb4449f", "notes": "Corrects the iicbb-pass lead (no NULL-ivars deref on DragonFly; the accessor routes through BUS_READ_IVAR). Bucket suggestion: base:hw (family-consistent). The finding also documents why /dev/iicN is effectively dead on stock DragonFly, which suppressed field reports of the iic.c ioctl bugs.", "recommended_fix": "Implement bus_read_ivar/bus_write_ivar on the iicbus driver returning a sane default (0) for IICBUS_IVAR_ADDR when no ivars exist (see fix.diff); longer term, allocate iicbus_ivar for children in bus_add_child as FreeBSD does.", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff applied to the guests /usr/src copy of sys/bus/iicbus/iicbus.c; only iicbus.ko rebuilt (no kernel rebuild). Baseline stock: BUS_READ_IVAR ENXIO with *result untouched; iic child never attaches (240+ re-probes ENXIO); /dev/iic0 absent. Patched: BUS_READ_IVAR error=0 with *result=0 written; production iic.ko attaches on the first kldload; /dev/iic0 created and fully functional (DF-5558 PoC runs against it).", "fix_evidence": "fix.diff; ../DF-5558/fix_build.log (iicbus.ko rebuild); dmesg.txt (readivar: BUS_READ_IVAR error=0 ... v=0x0 (written)); stock-probe-evidence.log (baseline failures)." } |