{
  "finding_id": "DF-4582",
  "status": "inconclusive",
  "reproduced": 0,
  "impact": "panic",
  "confidence": "likely",
  "verdict": "Primitive PROVEN on the guest: the byte-identical rs690_crtc_bandwidth_compute() (verbatim extraction, kernel build flags) executed in the live guest kernel with the attacker-shaped mode->clock=1048576 kHz (2^20) takes Fatal trap 18: integer divide fault at dfixed_div+0xa divq \u2014 guest down (panic.txt, run.log). The SHIPPED /boot/kernel/radeon.ko disassembly independently confirms the reachable runtime division: 0x5ac39-0x5ac61 loads mode->clock, applies the truncating shl $0xc (dfixed_const), strength-reduces only the inner by-constant division, and emits a real div %rcx whose divisor is exactly zero for clock \u2261 0 (mod 2^20). Every hop of the unprivileged chain is source-proven (SETCRTC needs only DRM master = first opener; drm_mode_convert_umode rejects only clock>INT_MAX; drm_mode_validate_basic only clock==0; radeon sets no mode_config.funcs->mode_valid; bandwidth_update is reached from every modeset via the PROFILE pm path). The single missing hop is hardware: the QEMU guest has no RS690/RS740/RS780/RS880 IGP (virtio-vga only, /dev/dri absent), so the end-to-end ioctl chain could not be executed \u2014 hence inconclusive rather than reproduced. Ceiling = local kernel panic (DoS), no memory corruption.",
  "exploit_chain": "open /dev/dri/cardN (first opener => DRM master) -> DRM_IOCTL_MODE_SETCRTC with umode.clock=1048576 kHz, sane h/v timings (passes drm_mode_convert_umode ERANGE + drm_mode_validate_basic clock!=0; radeon has no mode_valid) -> crtc helpers commit mode (encoder fixups unconditional, PLL best-effort) -> atombios_crtc_dpms -> radeon_pm_compute_clocks -> radeon_pm_compute_clocks_old PROFILE -> radeon_pm_set_clocks -> radeon_bandwidth_update (radeon_pm.c:312) -> rs690_bandwidth_update (rs690.c:583; asic map radeon_asic.c:727 RS690/RS740, :1138 RS780/RS880) -> rs690_crtc_bandwidth_compute rs690.c:326-329: dfixed_const(1048576)=(u32)(2^20<<12)=0 -> dfixed_div(1000,0) -> do_div by zero (drm_fixed.h:62-70 + math64.h:36-42) -> integer divide fault -> kernel panic.",
  "evidence": "panic.txt (Fatal trap 18, Stopped at dfixed_div+0xa: divq %rsi,%eax); run.log (decisive kernel run); run.2.log (-O0 userland SIGFPE x3 + codegen notes); objdump_radeon_ko.txt (SHIPPED binary: 0x5ac41 shl $0xc truncating shift, 0x5ac61 div %rcx runtime zero divisor; 0x5adb9 div %r8 for the DF-4583 sideport sink); fix_run.log (WITH_FIX build survives all scenarios with guard messages, clean unload); rs690_div0_body.h (verbatim extraction, byte-identical function body).",
  "kernel_refs": [
    "sys/dev/drm/radeon/rs690.c:326-329",
    "sys/dev/drm/radeon/rs690.c:583-648",
    "sys/dev/drm/include/drm/drm_fixed.h:35",
    "sys/dev/drm/include/drm/drm_fixed.h:62-70",
    "sys/dev/drm/include/linux/math64.h:36-42",
    "sys/dev/drm/drm_crtc.c:655",
    "sys/dev/drm/drm_modes.c:1114",
    "sys/dev/drm/drm_modes.c:1696",
    "sys/dev/drm/radeon/radeon_display.c:1350-1353",
    "sys/dev/drm/drm_ioctl.c:656",
    "sys/dev/drm/radeon/radeon_pm.c:311-312",
    "sys/dev/drm/radeon/radeon_pm.c:1729-1755",
    "sys/dev/drm/radeon/atombios_crtc.c:296",
    "sys/dev/drm/radeon/radeon_asic.c:727",
    "sys/dev/drm/radeon/radeon_asic.c:1138"
  ],
  "poc_changes": "No seed PoC existed (pass-1 file was clean). Authored from scratch: verbatim extraction of rs690_crtc_bandwidth_compute + dfixed/do_div helpers into a standalone header; userland driver (fork per scenario) and DragonFly KLD with runtime sysctl scenario selection (df4582.run). Two build-context fixes were required and are documented: (1) do_div/lower_32_bits must be defined before dfixed_div (include order mirrors the kernel build); (2) dfixed_div is noinline in the KERNEL harness build so gcc cannot UB-fuse the inner by-constant division with the outer runtime division \u2014 the shipped radeon.ko build emits exactly this unfused shape (see objdump_radeon_ko.txt); a first attempt also lost -DDF4582_FIXED because kmod.mk reassigns CFLAGS (Makefile now appends after the include).",
  "attempts": 4,
  "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": 2400,
  "guest_dirty": 0,
  "build_cmd": "cc -O0 -o rs690_div0 rs690_div0.c && make && make WITH_FIX=1",
  "run_cmd": "./rs690_div0 ; kldload ./df4582_div0.ko && sysctl df4582.run=0   (fixed: for s in 0 1 2; do sysctl df4582.run=$s; done; kldunload df4582_div0)",
  "code_hash": "e2532b90882337cdb258c13e981adf2c99d367e04f376a673141d6af92693e43",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Harness-level fix validation on the guest kernel: the unpatched build of the same verbatim-function KLD panics with Fatal trap 18 (baseline_reproduced=1); the build carrying the fix.diff guards survives all three scenarios with DF4582-FIX: zero divisor avoided ... bailing with safe watermark and unloads cleanly (patched_reproduced=0). Full-hardware validation was not possible (no RS690-class IGP in the guest); the guard is input-independent (checks the computed fixed-point value, not the raw clock), so it covers every wrap multiple and any other zero-producing input.",
  "fix_evidence": "fix_run.log (guard messages x3 + clean unload) vs panic.txt/run.log (baseline trap 18); fix.diff (guard after the clock->fixed conversion at rs690.c:328, mirroring the disabled-CRTC safe-watermark bail at rs690.c:283-287).",
  "notes": "Hardware preconditions: RS690/RS740 or RS780/RS880 IGP with radeon KMS + local access to /dev/dri/cardN. RS780/RS880 were mass-market chipsets (780G/785G). Ceiling is local DoS (kernel panic), not memory corruption. DragonFly devfs typically grants the card node to group operator/video \u2014 standard for console users. Same wrap family exists in any other dfixed consumer that feeds user-controlled ints >= 2^20 into dfixed_const before a dfixed_div (this file is the one with a proven unfiltered path).",
  "recommended_fix": "rs690.c: after a.full = dfixed_div(a, b) of the pixel clock, bail with the disabled-CRTC safe watermark when a.full == 0 (dfixed_const 32-bit shift wraps clocks >= 2^20 kHz to zero); same guard class for the VBIOS-derived divisors (see DF-4583)."
}