DF-3280 / verdict.json
{ "finding_id": "DF-3280", "status": "reproduced", "reproduced": 1, "impact": "leak", "confidence": "certain", "verdict": "REPRODUCED on stock INVARIANTS guest (kernel #0 Jul 2 2026): an unprivileged SIOCGIFGMEMB reader racing a privileged group create/destroy churn receives data read through a dangling struct ifg_group pointer (if_getgroupmembers caches ifg at if.c:1324, releases ifgroup_lock at if.c:1337, walks ifg->ifg_members at if.c:1352 after the group may have been kfree()d by if_destroygroup if.c:1139). Three independent baseline runs: 2, 9, 3 stale reads (ANOMALY member= where only lo0 is possible). No panic in ~10^7 cycles: the 48-byte M_IFNET bucket is type-stable (freed chunks recycled as recreated group objects), and every destroy path is privileged (SYSCAP_NONET_IFCONFIG / if_detach), so the primitive is capped at stale kernel-heap disclosure to an unprivileged reader - no uid0 chain exists (documented hard blockers). fix.diff (re-lookup + recount under the re-acquired lock, mirroring safe if_getgroups) built into kernel #1 Sep 10 03:02:42: 0 anomalies over 1315 successful fetches while 3.0M add/del churn cycles ran error-free. Guest reset clean.", "exploit_chain": "unpriv reader -> SIOCGIFGMEMB phase-2 ioctl -> kernel walks freed ifg_group -> copies freed/reused heap contents (interface-name strings) to user. No escalation chain: (1) group destruction requires root on the mutator side (SIOCDIFGROUP SYSCAP_NONET_IFCONFIG at if.c:2396; if_detach teardown), (2) type-stable bucket reuse prevents pointer-controlled corruption, (3) window is ~us and only readable, not writable, from the unprivileged side.", "evidence": [ "run.log / run.2.log / run.3.log: ANOMALY member[0]=... lines from 3 independent baseline runs (2+9+3 events)", "VERDICT.md: full mechanism with path:line and fix-validation narrative", "run.fix.log: anom=0 after 1315 ok fetches on fix kernel #1", "churnFIX.log: 3.0M add/del cycles err=0 on fix kernel", "fix.diff: re-lookup+recount under re-acquired ifgroup_lock" ], "kernel_refs": [ "sys/net/if.c:1324", "sys/net/if.c:1337", "sys/net/if.c:1346", "sys/net/if.c:1352", "sys/net/if.c:1366", "sys/net/if.c:1234", "sys/net/if.c:1139", "sys/net/if.c:1289" ], "poc_changes": "group names may not end in a digit (if.c:1155 rejects, and the EINVAL error return leaks ifnet_mtx via known DF-0272 - first attempt wedged the guest); reader made robust against ENOENT spam (stats at loop top); churn takes group/ifp via argv; single churn per ifp+group to avoid EEXIST (also a DF-0272 landmine).", "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": 495, "guest_dirty": 0, "build_cmd": "cc -O2 -o /root/gmembr_churn /root/gmembr_churn.c && cc -O2 -o /root/gmembr_reader /root/gmembr_reader.c", "run_cmd": "(root) nohup /root/gmembr_churn rgrpA lo0 & ; (unpriv) /home/maxx/gmembr_reader rgrpA", "code_hash": "sha256:3a78a9323e590d4db7d80e6446ed5817c07f027701ccb92d0070488e8ec49704 (gmembr_reader.c), sha256:d70f9d94c1b4e7f1a8f1f8b74a47452a948dbedf396f178fffc844ae76bcad3d (gmembr_churn.c)", "notes": "Known-findings fix status observed live: DF-0272 unfixed and trivially reachable on stock guest (any SIOCAIFGROUP error return permanently wedges ifnet_mtx; seen twice during bring-up, D-state wchan ifnet); DF-0273/DF-0274 also unfixed in tree. sa_equal (sys/sys/socket.h:247) bcmps a1->sa_len bytes - same sa_len-trust family as DF-0274 (SIOCDELMULTI OOB bcmp read), folded into that findings fix scope, not re-reported. Fix build: make nativekernel 1556s + installkernel + reboot (kbuild.log).", "recommended_fix": "In if_getgroupmembers(), re-look up the group in ifg_head and recompute/verify the member count under the re-acquired ifgroup_lock before filling the reply (see fix.diff); mirror of the safe pattern already used by if_getgroups().", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Thu Sep 10 03:02:42 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff applied to guest /usr/src/sys/net/if.c, kernel rebuilt (make nativekernel KERNCONF=X86_64_GENERIC, BUILD-EXIT=0) and installed; exact PoC re-run on kernel #1: 0 anomalies across 1997 iterations / 1315 successful fetches in 110s (baseline: 2/9/3 anomalies), churn error-free 3.0M cycles. Bad behavior GONE, group API preserved.", "fix_evidence": "run.fix.log (anom=0), churnFIX.log (adds=dels=3030847 err=0), kbuild.log (BUILD-EXIT=0), fix_validation.diff (combined applied diff)" } |