⬢ DragonFlyBSD Kernel Audit
DF-4493 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-4493",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "Reproduced at logic level with the verbatim replica (harness modes 4493/4493b): a PowerPlayInfo table with no BOOT-classified state leaves rdev->pm.dpm.boot_ps NULL (rs780_dpm.c:741-742 is the only assignment), radeon_pm_init_dpm discards the init return (radeon_pm.c:1448) and still calls radeon_dpm_enable (:1453) -> rs780_get_ps(NULL) reads NULL->ps_priv at 0x28 -> SIGSEGV (kernel: page-fault panic); ucStateEntrySize==1 makes the `if (ucStateEntrySize - 1)` guard (:822) skip every state while num_ps is still set (:842), leaving all ps_priv NULL -> rs780_dpm_print_power_state :946 derefs ps->sclk_low at 0x8 -> SIGSEGV. Fault addresses match the kernel struct layouts exactly (offsetof radeon_ps.ps_priv = 40, igp_ps.sclk_low = 8). RS780 twin of DF-4187 (sumo) / DF-4124 (rv6xx) / DF-4143 (trinity) / DF-4118 (cypress). Kernel-level repro hardware-gated (no RS780 IGP in the QEMU guest). Fix proven: enable refuses NULL boot_ps; parse rejects ucStateEntrySize < 2; radeon.ko builds under -Werror (MAKE_RC=0).",
  "exploit_chain": "crafted VBIOS PowerPlayInfo (no BOOT class, or ucStateEntrySize==1) -> parse returns success with boot_ps/ps_priv NULL -> radeon_pm.c:1448 swallows nothing to swallow (parse succeeded) -> dpm enable runs -> NULL->ps_priv read at 0x28 -> kernel page-fault panic (local DoS on probe / first mode set / radeon_dpm=1 boot print)",
  "evidence": "run.log ===== mode 4493 =====: boot_ps=0x0 then SIGNAL 11 at address 0x28, exit=99; ===== mode 4493b =====: ps[0].ps_priv=0x0 then SIGNAL 11 at address 0x8, exit=99; fixed sections: DRM_ERROR: no boot power state, refusing to enable DPM / DRM_ERROR: invalid state entry size 1, exit=0; radeon_module_build.log MAKE_RC=0 under -Werror",
  "kernel_refs": [
    "sys/dev/drm/radeon/rs780_dpm.c:600",
    "sys/dev/drm/radeon/rs780_dpm.c:608",
    "sys/dev/drm/radeon/rs780_dpm.c:78",
    "sys/dev/drm/radeon/rs780_dpm.c:822",
    "sys/dev/drm/radeon/rs780_dpm.c:842",
    "sys/dev/drm/radeon/rs780_dpm.c:946",
    "sys/dev/drm/radeon/radeon_pm.c:1448"
  ],
  "poc_changes": "wrote harness from scratch (no seed); -fno-delete-null-pointer-checks + volatile clock sink required so the NULL loads trap with kernel semantics instead of being folded by GCC",
  "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": 200,
  "guest_dirty": 0,
  "build_cmd": "./build.sh (on audit guest, cc 8.3, -fno-delete-null-pointer-checks)",
  "run_cmd": "./run.sh  (modes 4493 4493b; full matrix in run.log)",
  "code_hash": "3b7698d1a8d20944dd3c2ea4c0010146536ed001ff5cf1034c4c4ac650591741",
  "notes": "known finding DF-1650 excluded (pass-1). Trigger B (ucStateEntrySize==1) additionally leaves every ps_priv NULL for set_power_state/get_sclk/force_performance_level consumers; trigger A covers the DF-4187 shape. Both die on the same unchecked rs780_get_ps() contract.",
  "recommended_fix": "refuse to enable DPM without a boot power state (boot_ps NULL check in rs780_dpm_enable) and reject ucStateEntrySize < 2 in rs780_parse_power_table, as in fix.diff",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "harness_fixed 4493 returns -EINVAL before any deref (no boot power state); 4493b rejected at parse (invalid state entry size 1); combined fix builds radeon.ko under -Werror (MAKE_RC=0)",
  "fix_evidence": "run.log fixed sections for modes 4493/4493b (exit=0, canary_violations=0); radeon_fix_apply.log hunk 1 (enable guard) and hunk 4 (entry-size check); radeon_module_build.log MAKE_RC=0"
}