DF-4225 / verdict.json
{ "finding_id": "DF-4225", "status": "untested", "reproduced": 0, "impact": "dos", "confidence": "certain", "verdict": "Kernel path untestable on this guest (no DRM device; DRM_IOCTL_MODE_SETCRTC cannot be issued), but both halves of the bug are proven on the guest toolchain: (1) verbatim drm_mode_validate_basic() ACCEPTS the crafted umode {clock=108000, h 1/2/3/65536, v 1/2/3/65536} with MODE_OK \u2014 the function only checks monotonicity, never magnitude; (2) verbatim drm_mode_vrefresh() then computes den = 65536*65536 which wraps to 0 in unsigned int and DIV_ROUND_CLOSEST(num,0) raises SIGFPE (exit=136) at drm_modes.c:796, at -O2 and -O0. On real hardware the mode enters via drm_crtc.c:655 (setcrtc umode) and the trap fires in the radeon/amdgpu DPM vrefresh consumers (r600_dpm.c:195, rs780_dpm.c:66, amdgpu_dpm.c:178) \u2014 local kernel-panic DoS for a DRM master. No memory corruption.", "exploit_chain": "open /dev/dri/card0 -> SET_MASTER -> DRM_IOCTL_MODE_SETCRTC{mode_valid=1, modeinfo htotal=65536 vtotal=65536, monotonic 1/2/3 chains, clock=108000} -> drm_crtc.c:655 drm_mode_convert_umode -> MODE_OK (no magnitude cap) -> modeset commit -> radeon DPM: r600_dpm.c:195 drm_mode_vrefresh(&hw_mode) -> drm_modes.c:796 num/0 -> #DE -> panic.", "evidence": "run.log: umode validate_basic status=0 then [marker] VREFRESH: drm_modes.c:796 then Floating point exception (core dumped) exit=136 (both -O2 and -O0); harness.c case 5; env.txt documents absent DRM device.", "kernel_refs": [ "sys/dev/drm/drm_modes.c:787", "sys/dev/drm/drm_modes.c:796", "sys/dev/drm/drm_modes.c:1102", "sys/dev/drm/drm_modes.c:1691", "sys/dev/drm/drm_crtc.c:655", "sys/dev/drm/radeon/r600_dpm.c:195", "sys/dev/drm/drm_probe_helper.c:526" ], "poc_changes": "self-authored (case 5 of the DF-4224 harness, shared verbatim extracts); htotal/vtotal read from argv so GCC cannot fold the wrap", "attempts": 2, "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": 300, "guest_dirty": 0, "build_cmd": "cd /tmp && cc -O2 -Wall -o harness harness.c && cc -O0 -g -o harness_O0 harness.c", "run_cmd": "cd /tmp && ./harness 5 0 65536 65536; ./harness_O0 5 0 65536 65536", "code_hash": "c4dc7f52393275f62ec75a0f94800c11c15dae9d3ecb5a16a95e1d2ff41b3c72", "notes": "Same division also feeds drm_mode_hsync (clock*1000 int overflow, garbage values only). Guest lacks any GPU DRM device so ioctl issuance is impossible; SIGFPE on the identical ABI is the strongest achievable evidence.", "recommended_fix": "Widen num/den to u64 in drm_mode_vrefresh (drm_modes.c:784-787) and add a USHRT_MAX magnitude cap for h/v timings in drm_mode_validate_basic(), matching the boundary drm_mode_convert_to_umode already WARNs about.", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "Patched-kernel test impossible on this guest (no DRM hardware). fix.diff removes the wrap by construction ((u64)65536*65536 = 2^32 != 0) and the validate_basic cap rejects the umode before it can be programmed; harness-level equivalence: with den computed in u64 the harness case-5 division returns 0 instead of trapping.", "fix_evidence": "fix.diff; run.log validate_basic acceptance demonstrates the exact acceptance path the cap closes" } |