DF-4023 / verdict.json
{ "finding_id": "DF-4023", "status": "inconclusive", "reproduced": 0, "impact": "none", "confidence": "certain", "verdict": "Source-level certain mechanism, runtime hardware+OOM-gated (inconclusive per family convention). rv7xx_parse_power_tables per-state kzalloc failure path (rv770_dpm.c:2306-2310) kfrees rdev->pm.dpm.ps WITHOUT NULLing it and WITHOUT freeing the ps_priv[0..i-1] already stored; num_ps is set only after the loop (:2327) so it stays 0. rv770_dpm_init propagates the error (:2368-2370) but radeon_pm_init_dpm IGNORES dpm.init failure (radeon_pm.c:1448) and proceeds to enable; when enable fails GRACEFULLY before the init_smc_table NULL deref (rv770_construct_vddc_table -EINVAL at rv770_dpm.c:1912-1916, or rv770_upload_firmware failure at :1951-1955 with missing SMC ucode) attach completes with dpm_enabled=false and ps dangling. At unload/reboot: rv770_fini (rv770.c:1996-1998) -> radeon_pm_fini (radeon_pm.c:1721-1724) -> radeon_pm_fini_dpm -> radeon_dpm_fini UNCONDITIONALLY (radeon_pm.c:1705) = rv770_dpm_fini (rv770_dpm.c:2543-2552): num_ps==0 skips the ps_priv loop (i parsed states LEAK), then kfree(rdev->pm.dpm.ps) at :2550 DOUBLE-FREES the block freed at :2308 -> kmalloc heap corruption/panic at detach. Shared root site of the DF-3645/3755/3955/3973 family as DF-3973s notes anticipated; the rv770-family dispatch consumption is new. Trigger class identical to the accepted ni/kv twins (alloc-failure window during attach).", "exploit_chain": "On RV770-family hardware: many-state crafted VBIOS + boot-time kernel memory pressure forcing the kzalloc at :2306 to fail; graceful enable failure keeps the driver attached; kldunload/reboot double-frees the ps array (heap metadata corruption -> panic; root-gated trigger point, so realistic ceiling is DoS at unload/reboot) plus i*sizeof(rv7xx_ps) permanent leak.", "evidence": "VERDICT.md (full chain with path:line); env.txt (hardware absence + md5 match); fix.diff (error-path cleanup + idempotent fini, git apply --check clean)", "kernel_refs": [ "sys/dev/drm/radeon/rv770_dpm.c:2289", "sys/dev/drm/radeon/rv770_dpm.c:2306", "sys/dev/drm/radeon/rv770_dpm.c:2308", "sys/dev/drm/radeon/rv770_dpm.c:2327", "sys/dev/drm/radeon/rv770_dpm.c:2368", "sys/dev/drm/radeon/rv770_dpm.c:1912", "sys/dev/drm/radeon/rv770_dpm.c:1951", "sys/dev/drm/radeon/rv770_dpm.c:2543", "sys/dev/drm/radeon/rv770_dpm.c:2550", "sys/dev/drm/radeon/radeon_pm.c:1448", "sys/dev/drm/radeon/radeon_pm.c:1705", "sys/dev/drm/radeon/rv770.c:1996" ], "poc_changes": "No seed PoC. No runnable PoC: needs RV770-family hardware plus a kzalloc failure inside the parse loop; pack follows the DF-3973 convention.", "attempts": 1, "guest_uname": "DragonFly dfbsd 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": 15, "guest_dirty": 0, "build_cmd": "n/a (hardware-gated)", "run_cmd": "n/a (hardware-gated)", "code_hash": "", "notes": "Pass-2 checklist item (a) for rv770_dpm.c, answering the orchestrators question: YES, DF-3973s shared root site (ps kfree without NULL) lives in THIS file at rv770_dpm.c:2308; the r600_free_extended_power_table un-NULLed-pointer half of DF-3973 is btc-specific (rv770_dpm_fini never calls it -- rv7xx parse allocates no extended dyn_state pointers).", "recommended_fix": "Free the already-parsed ps_priv states, NULL rdev->pm.dpm.ps on the parse error path, and make rv770_dpm_fini idempotent (see fix.diff; pair with DF-4022s init-error propagation).", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff applies clean against the read-only tree; cannot be runtime-validated without radeon hardware and a controlled attach-time alloc-failure window.", "fix_evidence": "findings/poc/DF-4023/fix.diff" } |