DF-3665 / verdict.json
{ "finding_id": "DF-3665", "status": "inconclusive", "reproduced": 0, "impact": "dos", "confidence": "likely", "verdict": "Kernel-path trigger is hardware-bound (guest is virtio-only: no radeon device, no /dev/dri, no drm kmods), so the panic itself cannot be executed here; the root cause and the divide are fully proven. evergreen_latency_watermark() (evergreen.c:2048-2049) divides by evergreen_available_bandwidth(), which verbatim-math simulation on the guest shows is ZERO for (a) a DRM-master user mode with pixel clock <= 38 kHz - drm_mode_validate_basic() only rejects clock==0 and radeon registers no mode_valid hook (radeon_display.c:1350); (b) mclk/sclk in the u32 fixed20_12 dfixed_const() wrap windows (exactly 524288/1048576/1572864 kHz and k*2^20/10 bands; 351 mclk and 156 sclk killer values in 0..4 GHz); (c) VBIOS-reported zero clocks. The exact evergreen.c:2048 division was executed in forked children (divisor fed via pipe so GCC cannot fold it) and 9/9 divisor-zero scenarios died with SIGFPE - the userspace face of the kernel #DE panic. Controls (typical clocks) returned nonzero bandwidth and did not trap, confirming the boundary (clock 38 kHz -> 0, 39 kHz -> 1). Impact ceiling: reliable local kernel-panic DoS via DRM_IOCTL_MODE_SETCRTC by any DRM master, or boot/first-modeset panic on unlucky VBIOS DPM clocks. No corruption, no escalation.", "exploit_chain": "", "evidence": "run.log: every available_bandwidth=0 ... child killed by SIGFPE line (9 scenarios incl. clock=25 kHz and mclk=524288 kHz; controls at top return 2851/1900/487); df3665.c: verbatim port of drm_fixed.h u32 fixed-point + evergreen.c:1929-2017 bandwidth functions; VERDICT.md: full path:line proof chain atombios_crtc.c:1448 -> evergreen.c:2303/2323/2216/2048; fix.diff: zero-guard patch", "kernel_refs": [ "sys/dev/drm/radeon/evergreen.c:2048", "sys/dev/drm/radeon/evergreen.c:2049", "sys/dev/drm/radeon/evergreen.c:2016", "sys/dev/drm/radeon/evergreen.c:1989", "sys/dev/drm/radeon/evergreen.c:2163", "sys/dev/drm/include/drm/drm_fixed.h:35", "sys/dev/drm/drm_modes.c:1114", "sys/dev/drm/radeon/radeon_display.c:1350", "sys/dev/drm/radeon/atombios_crtc.c:1448" ], "poc_changes": "Seed sketch was rewritten from scratch: initial draft inlined dfixed_div(dfixed_const(7), ...) which does not type-check (kernel assigns to fixed20_12 temps first) - fixed to mirror kernel statements; the first SIGFPE demo was silently dead-code-eliminated by GCC 8.3 (unused division result), the second was value-range-folded (comparison provably false) - fixed by feeding the divisor through a pipe and deriving the child exit code from the quotient bits, forcing a real idiv; added control scenarios and the 39 kHz boundary case.", "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": 240, "guest_dirty": 0, "build_cmd": "cc -O2 -Wall -o df3665 df3665.c", "run_cmd": "./df3665", "code_hash": "5a6def81f32aa6ab2f6cfbdc7419439645f1ba3d616b56e2827802213de1ff6e", "notes": "Guest has no radeon hardware (vgapci0 = virtio-gpu 0x11111234; /dev/dri absent; no drm kmods) - kernel-path execution impossible, hence inconclusive per audit convention for hardware-absent targets, not not_testable. Same-class precedent findings: DF-1386, DF-1650, DF-1137. The u32 fixed20_12 wrap also corrupts all DCE4/5 watermark values above 104.86 MHz inputs (correctness issue shared with upstream); only the zero windows are security-relevant.", "recommended_fix": "Guard the divisors in evergreen_latency_watermark(): if (!available_bandwidth || !wm->disp_clk) return 0; before the two divisions at evergreen.c:2048-2050", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff adds the zero-guard before the divisions; cannot be kernel-tested on this guest (no radeon device to reach evergreen_bandwidth_update), but the guard provably makes the zero-divisor paths return early - the exact condition the PoC demonstrates traps without it.", "fix_evidence": "fix.diff; VERDICT.md Fix section; PoC controls show nonzero-divisor behavior unchanged" } |