DF-5643 / verdict.json
{ "finding_id": "DF-5643", "status": "reproduced", "verdict": "REPRODUCED on the stock kernel (same rig as DF-5642): smbus_detach (smbus.c:105-115) never checks struct smbus_softc.owner (smbus.h:34), so device_detach(smbus0) succeeds under a verifiable owner and device_detach -> device_set_driver(dev, NULL) (subr_bus.c:2150) -> kfree(dev->softc) (subr_bus.c:1941-1946) frees the softc underneath. RUN B: the owners release -- the exact smbioctl exit path (smb.c:356) -- page-faults reading sc->owner with sc=NULL: Fatal trap 12 ... Stopped at smbus_release_bus+0x78: cmpq %r13,(%r12) (smbconf.c:166), guest down in DDB. RUN C: an SMB_WAIT requester parked in tsleep(sc) (smbconf.c:93, ps shows df5642_park on smbreq) is never woken by the detach and keeps sleeping on the freed softc; a wakeup of the freed address resumes it INSIDE smbus_request_bus: it re-reads freed sc->owner (smbconf.c:128), takes the grant branch and WRITES its device_t into the freed M_BUS block (smbconf.c:134), returning SUCCESS (PARK-T: request RETURNED 0 (post-free resume)) -- a demonstrated post-free read+write; in production the stray wake is deliverable by any clients release because smbus_release_bus broadcasts wakeup(sc) unconditionally (smbconf.c:177) and the reallocated softc occupies the same address. fix.diff adds the EBUSY owner veto; on the patched kernel device_detach under owner returns 16, the softc stays intact (same address pre/post), the owners release returns 0 (no trap) and a parked waiter is granted properly on the live softc.", "reproduced": true, "impact": "panic", "confidence": "certain", "exploit_chain": "root (or hot-removal/rescan): kldunload of the bridge or any smbus0 detach while (a) a /dev/smbN ioctl holds the bus (smb.c:240..356) or (b) an ipmi_ssif/cyapa client owns/parks on it -> smbus_detach returns 0 -> softc freed -> owners smbus_release_bus NULL-derefs (Fatal trap 12, proven) / parked waiter sleeps unkillably on freed memory and, once woken by any releases wakeup(sc) broadcast on the reallocated block, reads garbage owner and writes its device_t into freed M_BUS heap (post-free write, proven) -- with M_BUS reuse the 8-byte pointer write lands in the next same-sizeclass allocation (softc-sized kernel object).", "evidence": "run_b.log + panic.txt (VETO: device_detach(smbus0)=0 <<< BUS DETACHED UNDER ITS OWNER, post-detach softc=0, Fatal trap 12 ... Stopped at smbus_release_bus+0x78: cmpq %r13,(%r12), fault virtual address 0x0); run_c.log (PARK-T: request RETURNED 0 (post-free resume) after WAKUAF: wakeup(freed sc=...), ps df5642_park smbreq); run_b_fixed.log (device_detach(smbus0)=16 (vetoed: GOOD), post-detach softc=0xfffff8008d382380 intact, RELFREE: returned 0); run_c_fixed.log (waiter granted on LIVE softc).", "kernel_refs": [ "sys/bus/smbus/smbus.c:105-115", "sys/bus/smbus/smbus.h:34", "sys/bus/smbus/smbconf.c:126-141", "sys/bus/smbus/smbconf.c:166", "sys/bus/smbus/smbconf.c:177", "sys/kern/subr_bus.c:2146-2150", "sys/kern/subr_bus.c:1941-1946", "sys/dev/smbus/smb/smb.c:240", "sys/dev/smbus/smb/smb.c:356" ], "poc_changes": "Rig shared with DF-5642 (see ../DF-5642/df5642_rig.c); ioctls GRAB/VETO/RELFREE/PARK/WAKUAF drive smbus_request_bus / device_detach / smbus_release_bus / kthread park + wakeup on the saved softc pointer. run_b.sh/run_c.sh in this pack.", "attempts": 2, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 (baseline) / #1: Fri Oct 9 04:55:10 UTC 2026 (fix)", "runtime_sec": 1500, "guest_dirty": 0, "build_cmd": "same rig build as DF-5642 (make -f Makefile SYSDIR=/usr/src/sys); fix kernel: patch -p1 < fix.diff && make -j6 nativekernel KERNCONF=X86_64_GENERIC && make installkernel", "run_cmd": "sh /root/df5642/run_b.sh (baseline: panic); sh /root/df5642/run_c.sh (baseline: freed-softc waiter); on patched kernel: run_b.sh + grab/park/veto/relfree sequence (fix validation)", "code_hash": "df5642_rig.c sha256 834f76e5c1304d5c5fa8aec937f675a64ab26bf53ff79d567627201c88529854; run_b.sh sha256 f28b115fdd62a00ab760e31a8dfb5ca25cf53d5d6eb05d073c4d39f30e123984", "notes": "DF-5635 twin at the smbus layer (there: swallowed detach error -> NULL softc deref at iicbus layer; here: missing owner veto -> freed softc under live clients) and DF-5508 twin (amdsmb no-drain). The parked-waiter shape compounds DF-5638 (unkillable smbreq park) with a lifetime bug: the park target itself is freed.", "recommended_fix": "Refuse detach while a client owns the bus: in smbus_detach, return EBUSY if ((struct smbus_softc *)device_get_softc(dev))->owner != NULL (fix.diff).", "fix_status": "fixed", "fix_baseline_reproduced": true, "fix_patched_reproduced": false, "fix_verdict": "With fix.diffs EBUSY owner veto in the guest kernel: device_detach under a verifiable owner returns 16, the softc remains allocated (same address), the owners release returns 0 (no trap), and a parked SMB_WAIT requester is granted correctly on the live softc after the owners release. Baseline trap + post-free write eliminated.", "fix_evidence": "run_b_fixed.log (device_detach(smbus0)=16 (vetoed: GOOD); post-detach softc=0xfffff8008d382380; RELFREE: returned 0); run_c_fixed.log (WAKUAF: after wakeup: done=1 error=0 on the live softc, same address pre/post veto)" } |