β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-5069

psm_fini_power_state_table() leaves hwmgr->boot_ps and hwmgr->uvd_ps dangling into the freed hwmgr->ps allocation (incomplete cleanup; no in-tree reader today)

Summary

fini NULLs request/ps/current but forgets the two interior pointers assigned from the ps array - no in-tree reader exists so latent UAF-shape only. NULL-them-too fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5069 Β· 5 files
FileTypeDescriptionSize
README.md β€” 999 B ↓ raw
VERDICT.md β€” 2.6 KB ↓ raw
fix.diff β€” 370 B view raw
verdict.json β€” 2.6 KB view raw
env.txt β€” 1.7 KB view raw

DF-5069 β€” psm_fini_power_state_table() leaves hwmgr->boot_ps / hwmgr->uvd_ps dangling after kfree(hwmgr->ps)

Build

Not buildable/runnable on the audit guest (requires AMD GPU / amdgpu attach β€” see env.txt; guest has only QEMU std VGA, /dev/dri absent).

Run

N/A β€” see env.txt.

Expected behavior

psm_fini_power_state_table() (pp_psm.c:94-109) frees hwmgr->ps (:104) and NULLs request_ps/ps/current_ps (:105-107) but leaves hwmgr->boot_ps and hwmgr->uvd_ps β€” assigned at pp_psm.c:79/:87 as pointers into the freed ps array β€” dangling. No in-tree reader of hwmgr->boot_ps/hwmgr->uvd_ps exists today (verified by grep across sys/dev/drm/amd: only the two assignments in pp_psm.c; the adev->pm.dpm.boot_ps family used by si/ci/kv_dpm.c is a different struct), so this is a defense-in-depth fix: the first future consumer of these published pointers would be a use-after-free read.

Fix

Apply fix.diff (NULL both pointers in psm_fini alongside the others).

VERDICT.md
↓ download raw

VERDICT β€” DF-5069 (pass 2, df-bsd-reviewer)

Status: untested (hardware-gated β€” requires amdgpu attach; guest has no AMD GPU, see env.txt). Defect existence: certain (dangling assignment is objective). Impact today: none β€” latent hardening; no in-tree reader of the dangling pointers exists.

Where the defect is (path:line)

sys/dev/drm/amd/powerplay/hwmgr/pp_psm.c:

 79:            hwmgr->boot_ps = state;      /* state walks the hwmgr->ps array */
 87:            hwmgr->uvd_ps = state;
...
102:    kfree(hwmgr->current_ps);
103:    kfree(hwmgr->request_ps);
104:    kfree(hwmgr->ps);                       <- the array boot_ps/uvd_ps point into
105:    hwmgr->request_ps = NULL;
106:    hwmgr->ps = NULL;
107:    hwmgr->current_ps = NULL;

boot_ps and uvd_ps are set as interior pointers of the kcalloc(table_entries, size) allocation made at :53; after psm_fini they reference freed memory while ps/request_ps/current_ps are properly NULLed. Fields are declared at inc/hwmgr.h:754-755.

Reachability analysis (why this is Info, not UAF)

grep over sys/dev/drm/amd for boot_ps/uvd_ps: - only writers: pp_psm.c:79 and pp_psm.c:87 (into struct pp_hwmgr); - the many other matches (si_dpm.c, ci_dpm.c, kv_dpm.c, amdgpu_pm.c, amdgpu_dpm.c/h) operate on adev->pm.dpm.boot_ps β€” a different field of the legacy dpm manager, never hwmgr->boot_ps.

So no current code dereferences the dangling pointers; the hazard materializes only for future consumers of the (published, header-declared) fields. Classic incomplete-cleanup / CWE-459 shape; fixing costs two lines. (Note: upstream Linux cross-check was attempted but web fetch of the upstream file was unavailable during this run β€” firecrawl backend refused, git.kernel.org/elixir under an anti-bot gate, raw.githubusercontent 429 β€” so the finding is argued purely on in-tree evidence.)

Why untested on the guest

pp_psm functions run only after amdgpu attach; guest has no AMD display device (pciconf chip=0x11111234 QEMU std VGA; /dev/dri absent; no drm attach in dmesg β€” env.txt). No runtime trigger exists; a fix-validation kernel rebuild without the hardware cannot demonstrate anything.

Fix (fix.diff)

    hwmgr->request_ps = NULL;
    hwmgr->ps = NULL;
    hwmgr->current_ps = NULL;
+   hwmgr->boot_ps = NULL;
+   hwmgr->uvd_ps = NULL;
    return 0;

Fix status (batch validation)

Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

Two-line NULLing fix, trivially correct by inspection; cannot be boot-validated on the audit guest (path requires an AMD GPU - env.txt).

findings/poc/DF-5069/fix.diff; VERDICT.md fix section.
↓ fix.diffper-fix-DF-5069

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md (assignments :79/:87 vs fini :102-107, reader-grep proving latency); env.txt (hardware-absence documentation); fix.diff (NULL both pointers in fini).

PoC changes

No PoC exists (latent hardening finding on a hardware-gated path). Evidence pack is analysis-only with hardware-absence documentation.

Verified recommended fix

NULL hwmgr->boot_ps and hwmgr->uvd_ps in psm_fini_power_state_table() alongside request_ps/ps/current_ps (pp_psm.c:105).

Verdict

psm_fini_power_state_table() (sys/dev/drm/amd/powerplay/hwmgr/pp_psm.c:94-109) frees hwmgr->ps at :104 and NULLs request_ps/ps/current_ps (:105-107) but leaves hwmgr->boot_ps and hwmgr->uvd_ps - assigned as interior pointers of that array at pp_psm.c:79/:87, declared at inc/hwmgr.h:754-755 - dangling into freed memory. Grep across sys/dev/drm/amd shows no in-tree reader of hwmgr->boot_ps/hwmgr->uvd_ps (the si/ci/kv/amdgpu_pm boot_ps uses are the separate adev->pm.dpm.boot_ps field), so this is latent incomplete cleanup (CWE-459 shape), not a live UAF. Hardware-gated path (amdgpu attach) absent from the audit guest (QEMU std VGA, /dev/dri absent - env.txt), so no runtime verification is possible. Upstream-Linux cross-reference was attempted but web retrieval was unavailable during this run (firecrawl backend refused; kernel.org/elixir anti-bot gate; raw.github 429); finding argued on in-tree evidence only.