⬢ DragonFlyBSD Kernel Audit
DF-3878 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-3878",
  "status": "not_reproduced",
  "reproduced": 0,
  "impact": "none",
  "confidence": "certain",
  "verdict": "Source-certain divide-by-zero in the DCE8 display watermark math, the direct DF-3828 (DCE11) / DF-3857 (DCE10) twin: dce_v8_0_latency_watermark() divides by available_bandwidth at dce_v8_0.c:817-818 and by wm->disp_clk at :819, all before the functions only guard (num_heads==0, :827, itself dead via the caller gate at :959) and with no divisor validation anywhere on the caller chain (mode set -> dce_v8_0_crtc_do_set_base :1973 -> dce_v8_0_bandwidth_update :1082 -> dce_v8_0_program_watermarks :948, plus the DPM recompute path amdgpu_pm.c:2141). Zero inputs traced end-to-end: with DPM disabled, wm.yclk/wm.sclk come from adev->pm.current_mclk/current_sclk (:973-974), seeded from VBIOS ulDefaultEngineClock/ulDefaultMemoryClock with no zero-guard (amdgpu_atombios.c:678/680) and assigned even on parse failure (:718-719) - identical to the DF-3828/3857 seeding; one zero term collapses dce_v8_0_available_bandwidth (:760-768) to 0 and the divide takes #DE -> kernel panic. The mode->clock==0 secondary vector is killed in this tree by drm_mode_validate_basic (drm_modes.c:1114) via drm_mode_convert_umode -> drm_mode_validate_driver (:1745). Which watermark function runs on DCE8 parts: verified that BONAIRE/KAVERI/KABINI/MULLINS take the legacy path by default (amdgpu_device.c:2304-2315 return amdgpu_dc > 0 with amdgpu_dc defaulting to -1), so dce_v8_0_latency_watermark IS live on those parts; CHIP_HAWAII defaults to DC and runs the DF-3869 dce_calcs family instead. Arithmetic primitive proven on the guest: exact replica of the bandwidth/watermark math traps SIGFPE (exit=136, signal 8 = #DE, dmesg-confirmed) 3/3 stress runs while the healthy-clock control returns normally (run.log, run.2.log, dmesg.txt). Kernel-path reproduction impossible on this guest - 0 AMD PCI devices, no /dev/dri (env.txt), amdgpu never binds - hence not_reproduced for the kernel reach; impact ceiling on Bonaire/Kaveri/Kabini/Mullins hardware in the zero-clock state: local DoS via panic by an unprivileged DRM client mode set.",
  "exploit_chain": "unprivileged user with /dev/dri/cardX access -> drm_mode_setcrtc -> dce_v8_0_crtc_do_set_base (:1973) -> dce_v8_0_bandwidth_update (:1082) -> dce_v8_0_program_watermarks (:948, gate at :959 passes for any enabled crtc with num_heads>=1) -> dce_v8_0_latency_watermark -> (512*8*1000)/available_bandwidth with available_bandwidth==0 -> #DE -> kernel panic. Precondition: pm.current_sclk or current_mclk == 0 (VBIOS zero default clocks or failed firmware-info parse with DPM off). Memory-safety impact: none (pure div0 DoS).",
  "evidence": "run.log (healthy control returns 2297, zero-clock input traps SIGFPE exit=136); run.2.log (3/3 stress traps); dmesg.txt (pid NNNN (wm_dce8), uid 1001: exited on signal 8 6x); env.txt (no AMD ASIC on guest); fix.diff (git-apply-clean); VERDICT.md (full chain + the dce10/11-template negative notes: hpd 0xff guards, audio pin[9]/num_pins<=7, afmt[9]/num_dig<=7, crtc_offsets[6], ISR src-id registration contract, pageflip read-before-check hardening note, LUT 256==gamma_size, cursor bounds)",
  "kernel_refs": [
    "sys/dev/drm/amd/amdgpu/dce_v8_0.c:817",
    "sys/dev/drm/amd/amdgpu/dce_v8_0.c:818",
    "sys/dev/drm/amd/amdgpu/dce_v8_0.c:819",
    "sys/dev/drm/amd/amdgpu/dce_v8_0.c:827",
    "sys/dev/drm/amd/amdgpu/dce_v8_0.c:959",
    "sys/dev/drm/amd/amdgpu/dce_v8_0.c:973",
    "sys/dev/drm/amd/amdgpu/dce_v8_0.c:1973",
    "sys/dev/drm/amd/amdgpu/amdgpu_atombios.c:678",
    "sys/dev/drm/amd/amdgpu/amdgpu_atombios.c:718",
    "sys/dev/drm/amd/amdgpu/amdgpu_device.c:2315",
    "sys/dev/drm/drm_modes.c:1114"
  ],
  "poc_changes": "Authored from scratch, modeled on the DF-3857 pack (no seed provided by orchestrator). Inputs via argv to defeat constant folding; dce_v8_0 line numbers and CIK dram-channel/bandwidth constants (dce_v8_0.c:642-768) adapted from this file; DC-vs-legacy boundary for DCE8 parts verified in-tree.",
  "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": 190,
  "guest_dirty": 0,
  "build_cmd": "vm.sh run_root cc -O2 -Wall -o /tmp/wm_dce8 /tmp/wm_dce8_div0.c",
  "run_cmd": "vm.sh run_user /tmp/wm_dce8; echo exit=$? (plus healthy-clock control and 3x stress; /tmp cleaned, cores removed)",
  "code_hash": "b151a0a83cc16d304b972b831a00ee661acbda8ea50de138bebe9232681eeece",
  "notes": "Pass-2 checklist item (DF-3828/3857 twin) for dce_v8_0.c. num_heads==0 guard placement confirmed dead via caller gate at :959. DC-vs-calcs boundary confirmed: legacy dce_v8_0 watermark math is the DEFAULT on Bonaire/Kaveri/Kabini/Mullins; Hawaii -> DC/dce_calcs (DF-3869 family). dce10/11-template negatives (hpd/audio/crtc array bounds, ISR registration contract) all verified clean, see VERDICT.md; pageflip crtcs[] read-before-check at :3083 noted as hardening-only (bounded by amdgpu_irq.c:426-431 dispatch contract, src_id in {8..18}).",
  "recommended_fix": "Bail out of dce_v8_0_latency_watermark when num_heads/disp_clk/available_bandwidth is 0 (mirroring and moving the existing guard before the divides), and zero-guard ulDefaultEngineClock/ulDefaultMemoryClock seeding in amdgpu_atombios_get_clock_info",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff guards all three divides (moving the num_heads guard before them, adding disp_clk and available_bandwidth checks) plus the VBIOS zero-clock seeding, and is git-apply-clean against the read-only sys/ tree; a patched-kernel build cannot be exercised on this guest (no AMD ASIC, amdgpu never attaches), so hardware fix validation is not_testable here",
  "fix_evidence": "fix.diff; VERDICT.md; env.txt (hardware gate)"
}