DF-2220 / verdict.json
{ "finding_id": "DF-2220", "status": "reproduced", "reproduced": 1, "impact": "denial_of_service", "confidence": "certain", "verdict": "Reproduced with the verbatim production kobject_init_and_add/kobject_release compiled kernel-resident. 16384 production-shape cycles (kmalloc container embedding the kobject, verbatim kobject_init_and_add naming it via the verbatim kvasprintf from drm_dragonfly.c, then the real kobject_put -> kref_put -> kobject_release chain whose release callback kfrees the container, exactly like ttm_bo_global_kobj_release) grow the M_DRM accounting by 655360 bytes = 40 bytes per cycle while the paired kmalloc/kfree control returns to 0 and the fix-2220 patched release (name pointer saved before the release call and kfree()d after, mirroring upstream kobject_cleanup) also returns to 0. Single-shot semantics: after the real kobject_release returns, the name allocation is still live and its content intact (leaked_name_probe_0123456789 read back after release); with the fixed release the meter returns to base. Slow unbounded kernel memory growth, root-gated (kldload/kldunload of drm modules or GPU attach cycles, ~5-7 kobjects per cycle); no UAF (the leaked buffer is simply lost), no corruption primitive, no privesc chain. Fix validated A/B in the same kernel.", "exploit_chain": "", "evidence": "run.log lines DF2220 CONTROL/BASELINE/FIXED/VERDICT: control delta=0, baseline delta=655360 (40/cycle, releases=16384 confirming the release path ran), BASELINE init:+32 after_release:+32 with content=[leaked_name_probe_0123456789] (allocation SURVIVED release), FIXED init:+32 after_release_fixed:+0, fixed loop delta=0; run.first_meterbug.log documents the corrected meter artifact", "kernel_refs": ["sys/dev/drm/linux_kobject.c:39", "sys/dev/drm/linux_kobject.c:45", "sys/dev/drm/linux_kobject.c:50", "sys/dev/drm/drm_dragonfly.c:67", "sys/dev/drm/include/linux/kobject.h:85", "sys/dev/drm/ttm/ttm_bo.c:1565", "sys/dev/drm/ttm/ttm_memory.c:257", "sys/dev/drm/ttm/ttm_page_alloc.c:838", "sys/kern/kern_slaballoc.c:202"], "poc_changes": "Rebuilt as verbatim-code kernel-compiled rig; carried the verbatim kvasprintf body (module-resident symbol) into the kernel TU; fabricated kobj_type release callbacks in both shapes (production container-freeing and non-freeing probe); deterministic M_DRM accounting meter", "attempts": 2, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Tue Oct 20 23:24:18 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/DFV22X x86_64", "runtime_sec": 15, "guest_dirty": 0, "build_cmd": "sh /root/poc/df22x/build.sh (nativekernel KERNCONF=DFV22X, rig compiled kernel-resident)", "run_cmd": "sh /root/poc/df22x/run.sh (sysctl kern.df22x_run=1 as root on the DFV22X harness kernel)", "code_hash": "c646506a8cbeda4dcb0ade737617a507fac86cf3d381b7df14e25aad5ab10fae", "notes": "Batch verification run with DF-2216/2223/2224 in the same harness kernel; guest reset with-src before return. Reachability requires drm module load/unload cycles (root) or GPU hotplug; ~40 bytes leaked per kobject release, 5-7 kobjects per drm subsystem lifecycle", "recommended_fix": "Save kobj->name before the type release callback and kfree(name, M_DRM) after it in kobject_release, mirroring upstream kobject_cleanup (see fix.diff)", "fix_status": "fixed", "fix_validated": 1, "fix_diff": "fix.diff" } |