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

smu10_hwmgr_backend_fini never frees vdd_dep_on_mclk β€” deterministic kernel heap leak per powerplay fini cycle on Raven APUs

Summary

populate_clock_table allocates seven dependency tables including vdd_dep_on_mclk at :443; backend_fini frees only the six siblings - the mclk free is absent (whole-tree search: alloc + two readers, never freed). Every hwmgr_hw_fini on Raven with valid SMC clock data leaks ~52 bytes permanently; unbounded across module reload/reinit. Also: the prior :851 count==0 lead is KILLED with reachability evidence (force_clock_level consumers all inside amdgpu_pm.c #if 0 sysfs blocks; debugfs off; no ioctl route). Add-the-missing-kfree fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4428 Β· 6 files
FileTypeDescriptionSize
README.md β€” 2.0 KB ↓ raw
VERDICT.md β€” 2.6 KB ↓ raw
env.txt β€” 164 B view raw
fix.diff β€” 398 B view raw
manifest.json β€” 1.1 KB view raw
verdict.json β€” 3.1 KB view raw

DF-4428 β€” smu10_hwmgr: vdd_dep_on_mclk never freed (deterministic kernel heap leak)

Finding (pass 2, GLM 5.3)

sys/dev/drm/amd/powerplay/hwmgr/smu10_hwmgr.c

  • smu10_populate_clock_table() allocates seven dependency tables when the SMC clock table is valid (:433-445): vdd_dep_on_dcefclk, vdd_dep_on_socclk, vdd_dep_on_fclk, vdd_dep_on_mclk (:443-445), vdd_dep_on_dispclk, vdd_dep_on_dppclk, vdd_dep_on_phyclk.
  • smu10_hwmgr_backend_fini() (:523-548) frees only six β€” the vdd_dep_on_mclk kfree is missing entirely (:528-539).

Every hwmgr_hw_fini() (hwmgr.c:258-259 β†’ backend_fini) on a Raven APU with a valid SMC clock table therefore leaks one kzalloc(4 + 12*NUM_MEMCLK_DPM_LEVELS) allocation (~52 bytes + kmalloc bucket overhead) into the kernel heap, forever. Reachable at driver fini / module unload / GPU reset re-init cycles (hwmgr_hw_init error paths also skip backend_fini, but the deterministic leak is the fini path itself).

Not an info leak; a resource lifetime bug found in the pass-2 lifetime/error-path sweep.

Evidence

Code-citation proof only β€” the audit QEMU guest has no AMD GPU (pciconf -l root-run shows no 0x1002 device, kldstat has no drm/amd modules; env.txt), so the amdgpu/powerplay backend cannot be instantiated there. The allocation/free asymmetry is directly visible at the cited lines and is compile-time deterministic (no runtime condition beyond "SMC clock table valid", which is the normal case on supported hardware).

Fix

fix.diff β€” add the missing kfree(pinfo->vdd_dep_on_mclk); NULL; pair (patch -p1 dry-run verified).

Run

No PoC program: a kernel-build + hardware run is required to observe the allocation count, and no Raven APU is available. verdict.json marks the PoC untested for exactly that reason; the finding itself is certain by inspection (allocation at :443, no matching free anywhere in the file β€” rg vdd_dep_on_mclk over the whole tree shows only populate, fini-miss, and the NULL-never-happens read sites).

VERDICT.md
↓ download raw

DF-4428 VERDICT β€” deterministic kernel heap leak: vdd_dep_on_mclk never freed

Reproduced?

Not run: the audit guest has no AMD GPU (root-run pciconf -l | grep -c 0x1002 = 0; no drm/amd modules in kldstat β€” env.txt), so the amdgpu powerplay backend for Raven cannot be instantiated on any available machine. The defect is static and certain by inspection:

  • Allocation: smu10_hwmgr.c:443-445 β€” smu10_get_clock_voltage_dependency_table(hwmgr, &pinfo->vdd_dep_on_mclk, NUM_MEMCLK_DPM_LEVELS, &smu10_data->clock_table.MemClocks[0]) β†’ kzalloc(4 + 12*4) (table_size math at :399, struct smu10_hwmgr.h:193-196 with entries[1] base).
  • Free: none. rg vdd_dep_on_mclk over the entire tree shows exactly three occurrences in this file β€” :443 (alloc), :990 and :1043 (readers in get_clock_by_type_with_latency/voltage). smu10_hwmgr_backend_fini() (:523-548) kfrees dcefclk, socclk, fclk, dispclk, dppclk, phyclk β€” six of the seven β€” and never mclk.
  • Trigger: hwmgr_hw_fini() (hwmgr.c:258-259) β†’ backend_fini on every amdgpu fini/unload when the SMC clock table was valid at populate time (table->DcefClocks[0].Freq != 0, smu10_hwmgr.c:433 β€” the normal case on Raven hardware). ~52 bytes + kmem bucket overhead leaked per cycle; unbounded across module reload / GPU reinit cycles.

Secondary (same lifetime sweep, not separately filed): when smu10_populate_clock_table() fails early (SMC comm fault) its caller smu10_hwmgr_backend_init() (:493) ignores the return value, leaving all seven pointers NULL; the readers at :990/:1043 and smu10_dpm_get_mclk (:709-712) then NULL-deref β€” firmware-fault class, hardware-gated, no attacker control on DragonFly (the sysfs paths that could push a crafted pp_table are #if 0 on DFly, see the :851 lead kill in the file's pass-2 notes).

Impact

Kernel memory leak (CWE-401), slow resource exhaustion on Raven APU systems across driver reload/resume-from-hardware-reset cycles. No info leak, no corruption. Severity Low.

Fix

fix.diff adds the missing kfree/NULL pair (patch -p1 dry-run verified against the read-only sys/ tree). Fix validation not run (no hardware): fix_status not_testable; the change is a two-line symmetric free matching the six sibling frees immediately above it.

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

No Raven hardware available to build/observe; fix is a two-line symmetric free identical in shape to the six adjacent frees, patch -p1 dry-run verified.

fix.diff
↓ fix.diffper-fix-DF-4428

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md allocation/free asymmetry walk; smu10_hwmgr.c:443 (alloc) vs :528-539 (six frees, mclk absent); env.txt guest hardware absence; fix.diff dry-run-verified two-line free

PoC changes

New pass-2 finding; no runtime PoC exists or is possible without Raven APU hardware. Evidence is code-citation based.

Verified recommended fix

Add kfree(pinfo->vdd_dep_on_mclk); pinfo->vdd_dep_on_mclk = NULL; to smu10_hwmgr_backend_fini next to the six sibling frees (fix.diff).

Verdict

Deterministic kernel heap leak in smu10_hwmgr_backend_fini: smu10_populate_clock_table allocates seven dependency tables including vdd_dep_on_mclk (smu10_hwmgr.c:443-445, kzalloc(4+12*NUM_MEMCLK_DPM_LEVELS)) but backend_fini (:523-548) kfrees only six - the vdd_dep_on_mclk free is missing, so every hwmgr_hw_fini (hwmgr.c:258-259) on a Raven APU with a valid SMC clock table leaks ~52 bytes + bucket overhead permanently. Whole-tree rg confirms exactly three vdd_dep_on_mclk occurrences in the file: alloc at :443 and readers at :990/:1043, no free. Not runtime-testable here: the audit guest has no AMD GPU (pciconf 0x1002 count=0, no drm/amd klds - env.txt), so the amdgpu/powerplay backend cannot be instantiated; the finding is certain by inspection and compile-time deterministic.