DF-4182 / verdict.json
{ "finding_id": "DF-4182", "status": "inconclusive", "reproduced": 0, "impact": "none", "confidence": "likely", "verdict": "Source-certain completion-path dead-end: radeon_flip_work_funcs enabled check (radeon_display.c:449) only guards the vblank wait loop; when the CRTC was disabled while the flip was pending the work still programs the flip on the disabled CRTC (:467) and sets flip_status=RADEON_FLIP_SUBMITTED (:469). A disabled CRTC raises no vblank/pflip irqs and radeon_crtc_handle_flip (:359/:381, the ONLY reset of flip_status anywhere in radeon) never runs: every later DRM_IOCTL_MODE_PAGE_FLIP on that CRTC returns EBUSY forever (:578-583), the queued vblank event is never delivered, and the drm_crtc_vblank_get reference taken by the ioctl core (drm_plane.c:1053) leaks (put is at :390 in the completion path). Unprivileged-reachable race (DRM master; window = fence wait, ms..s, widenable by GPU load). Local DoS of the CRTCs flip path until module reload. Not exercisable on this guest: no GPU, no /dev/dri (run.log).", "exploit_chain": "", "evidence": "VERDICT.md (state machine + grep proof that nothing else resets flip_status); rflip_wedge.c (race sequence + raw ioctl scaffolding); run.log (no GPU, build OK); fix.diff (radeon.h + radeon_display.c abort path) + fix_build.log (radeon.ko built -Werror with fix)", "kernel_refs": [ "sys/dev/drm/radeon/radeon_display.c:449", "sys/dev/drm/radeon/radeon_display.c:467", "sys/dev/drm/radeon/radeon_display.c:469", "sys/dev/drm/radeon/radeon_display.c:381", "sys/dev/drm/radeon/radeon_display.c:390", "sys/dev/drm/radeon/radeon_display.c:578", "sys/dev/drm/radeon/radeon_display.c:592", "sys/dev/drm/drm_plane.c:1053" ], "poc_changes": "n/a (first-pass PoC authored in this run; the full race needs libdrm modeset plumbing documented in README)", "attempts": 1, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 x86_64", "runtime_sec": 10, "guest_dirty": 1, "build_cmd": "cc -O -Wall -o rflip_wedge rflip_wedge.c", "run_cmd": "./rflip_wedge /dev/dri/card0 (full race needs libdrm: enable -> PAGE_FLIP -> disable -> re-enable -> PAGE_FLIP probe)", "code_hash": "9b1e36c87ccd319d466c263d085725b4601eedbc0d6b9d64d4f00cb914dc3008", "notes": "A narrow residual race remains after the fix (CRTC disabled between the enabled check and radeon_page_flip) - inherent to this legacy non-atomic flip design; the fix closes the persistent wedge which is the exploitable state. Related pin-leak shape: pflip_cleanups radeon_bo_reserve failure path (radeon_display.c:596-599) skips unpin, but reserve(intr=false) on a ww_mutex cannot fail there - dead code, not filed.", "recommended_fix": "Abort the flip in radeon_flip_work_func when !radeon_crtc->enabled: reset flip_status/flip_work, drm_crtc_vblank_put, deliver the event, unpin the new BO (stashed in struct radeon_flip_work) and queue the unpin work.", "fix_status": "inconclusive", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "Compile-validated only: fix.diff (radeon.h struct member + abort path in radeon_flip_work_func) applied cleanly and radeon.ko built with -Werror in the batch nativekernel build (fix_build.log). Behavioral test impossible on this guest (no GPU; race needs a real CRTC).", "fix_evidence": "fix_build.log excerpt (radeon_display.c -Werror KLD_MODULE compile + radeon.ko link)." } |