DF-4925 / verdict.json
{ "finding_id": "DF-4925", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "REPRODUCED against the stock /boot/kernel/amdgpu.ko: amdgpu_fbdev_init() stores adev->mode_info.rfbdev at amdgpu_fb.c:365 BEFORE the fallible drm_fb_helper_init() and, on its failure (:372-374), kfrees rfbdev without clearing the pointer; amdgpu_device_init() ignores the failure (amdgpu_device.c:2662), so the deferred teardown amdgpu_fbdev_fini() (amdgpu_device.c:2744) walked the dangling pointer in production code and double-kfreed it (deterministic slab panic memory chunk ... is already free! at amdgpu_fbdev_fini+0x78), and after a 0x41-filled same-size slab reclaim the teardown chased rfb.base.obj[0]=0x4141414141414141 into amdgpufb_destroy_pinned_object (GPF at movl -0x2d0(%rdi)) \u2014 a fully-controlled UAF walk. Exact amdgpu twin of the verified DF-4914 (radeon_fb).", "exploit_chain": "", "evidence": "panic-stage2.txt (double kfree: memory chunk 0xfffff800899945c0 is already free! with amdgpu_fbdev_fini+0x78 in the trace); panic-stage3.txt (RECLAIMED, 0x41-filled block, Fatal trap 9 ... Stopped at amdgpufb_destroy_pinned_object+0x1e: movl -0x2d0(%rdi),%eax); run.log (stage-1 dangling print, sizeof(struct amdgpu_fbdev)=592); build.log (clean module build); fix_build.log (patched amdgpu.ko builds and loads)", "kernel_refs": [ "sys/dev/drm/amd/amdgpu/amdgpu_fb.c:365", "sys/dev/drm/amd/amdgpu/amdgpu_fb.c:372", "sys/dev/drm/amd/amdgpu/amdgpu_fb.c:373", "sys/dev/drm/amd/amdgpu/amdgpu_fb.c:387", "sys/dev/drm/amd/amdgpu/amdgpu_fb.c:393", "sys/dev/drm/amd/amdgpu/amdgpu_device.c:2662", "sys/dev/drm/amd/amdgpu/amdgpu_device.c:2744", "sys/dev/drm/amd/amdgpu/amdgpu_device.c:2847", "sys/dev/drm/drm_fb_helper.c:871", "sys/dev/drm/drm_fb_helper.c:876", "sys/dev/drm/drm_fb_helper.c:884" ], "poc_changes": "No executable seed (fresh harness mirroring DF-4914s rfbuaf.c). Include flags taken verbatim from the in-tree sys/dev/drm/amd/amdgpu/Makefile; compiled and loaded first attempt.", "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": 1500, "guest_dirty": 0, "build_cmd": "cd /root/DF-4925 && sh build.sh (kmod make; production /boot/kernel/drm.ko + amdgpu.ko used as-is)", "run_cmd": "kldload drm && kldload amdgpu && kldload ./amdfbuaf.ko && sysctl hw.amdfbuaf=1 (stage 2: sysctl hw.amdfbuaf=2; stage 3 on fresh boot: sysctl hw.amdfbuaf=3)", "code_hash": "3f02cbaa2e14cf756a1dd136caf2880395782027a568915318f90153d961bf59", "notes": "Deferred detonation window is realistic on hardware: drm_fb_helper_init/-ENOMEM at driver load under memory pressure; failure ignored by amdgpu_device_init:2662; consumers at unload/reboot (amdgpu_fbdev_fini) and every suspend/eviction (amdgpu_fbdev_robj_is_fb). Guest reset (with-src) performed after the run.", "recommended_fix": "Clear adev->mode_info.rfbdev before kfree(rfbdev) in the drm_fb_helper_init error path of amdgpu_fbdev_init() (one line, see fix.diff).", "fix_status": "not_testable", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff (one line: adev->mode_info.rfbdev = NULL before kfree at amdgpu_fb.c:373) compiles and loads: patched guest /usr/src amdgpu_fb.c -> make BUILD_RC=0 -> patched amdgpu.ko loaded and ran alongside the PoC (fix_build.log, run.log). Dynamic baseline-vs-patched behavior cannot be shown on this guest by construction: the fix lives in amdgpu_fbdev_init()s error path, the entry to which (a graceful drm_fb_helper_init failure) cannot be induced live without an AMD GPU (allocators only fail catastrophically here), and the PoC injects the post-failure state directly \u2014 identical limitation as the verified DF-4914 twin. Behavior follows by inspection from the trace the PoC verified (store at :365, un-cleared free at :373, second free at :393).", "fix_evidence": "fix.diff (git-apply clean); fix_build.log (full build, BUILD_RC=0, patched amdgpu.ko linked); run.log stage-1 re-run against the patched module; VERDICT.md Fix validation section" } |