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

vega10_pp_tables_uninitialize leaks 8 subtable allocations (socclk/dcefclk/pixclk/phyclk/dispclk dep tables, pcie_table, valid_socclk_values, valid_dcefclk_values) on every pp_table reload / rebind cycle

Summary

The teardown frees only the 9 original allocations while the parser now kzallocs ~17: 8 subtable allocations are leaked per cycle. Trigger: every pp_table sysfs write (S_IWUSR) and every unbind/rebind - unbounded kernel-heap growth. Nothing else frees them. Add-the-8-kfree-pairs fix (git-apply OK, syntax-validated).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4397 Β· 9 files
FileTypeDescriptionSize
fix.diff β€” 1.0 KB view raw
vega10_processpptables_leakfix.c β€” 46.5 KB view raw
build_check.sh β€” 717 B view raw
build.log β€” 382 B view raw
env.txt β€” 417 B view raw
README.md β€” 1.8 KB ↓ raw
VERDICT.md β€” 2.2 KB ↓ raw
manifest.json β€” 1.1 KB view raw
verdict.json β€” 2.8 KB view raw

DF-4397 β€” vega10_pp_tables_uninitialize leaks 8 subtable allocations per reload

Severity: Low (root-triggered unbounded kernel-heap growth) | Confidence: certain

What

sys/dev/drm/amd/powerplay/hwmgr/vega10_processpptables.c:1183-1228: vega10_pp_tables_uninitialize() frees only 9 of the ~17 allocations made by vega10_pp_tables_initialize()/init_powerplay_extended_tables()/ init_dpm_2_parameters(). Leaked on every teardown/re-init cycle:

allocation site freed?
vdd_dep_on_sclk (931-934) yes
vdd_dep_on_mclk (959-962) yes
vdd_dep_on_socclk (926-929) NO
vdd_dep_on_dcefclk (954-957) NO
vdd_dep_on_pixclk (936-940) NO
vdd_dep_on_phyclk (942-946) NO
vdd_dep_on_dispclk (948-952) NO
pcie_table (964-967) NO
valid_socclk_values (986-988) NO
valid_dcefclk_values (1000-1002) NO
valid_sclk_values (993-995) / valid_mclk_values (1007-1009) yes
lookup tables Γ—3 (1108-1127) yes
mm_dep_table / tdp_table yes

Lifecycle: pp_dpm_set_pp_table (amdgpu_pm.c:676-700, sysfs pp_table, S_IWUSR) β†’ amd_powerplay_reset β†’ pptable_fini (hwmgr.c:261-281) + pptable_init β€” each reload leaks ~8 small allocations (typically a few hundred bytes to a few KB each, counts are u8-bounded). Rebind/ module reload cycles leak the same. Kernel-heap memory exhaustion over repeated root-triggered reloads (CWE-401). Upstream later rewrote this teardown to free everything.

Reproduce / validation

Static source diff (alloc list vs free list) is the proof β€” see VERDICT.md. Hardware-gated for runtime (no AMD GPU on the audit guest); fix.diff adds the 8 missing kfree pairs, git apply --check clean, and the patched file syntax-validates with 0 errors on the guest kernel toolchain (build.log).

VERDICT.md
↓ download raw

DF-4397 VERDICT β€” uninitialize leak

Status: untested (hardware-gated; source-certain) | confidence: certain

Root cause

vega10_pp_tables_uninitialize() (vega10_processpptables.c:1183-1228) was written against an older version of the parser and never grew with it. Every table produced by init_powerplay_extended_tables() is kzalloc'd (vega10_processpptables.c:308, 387, 535, 569, 610, 676, 733, 776, 838) but only the 9 originals are kfree'd:

leaked per cycle: vdd_dep_on_socclk, vdd_dep_on_dcefclk, vdd_dep_on_pixclk, vdd_dep_on_phyclk, vdd_dep_on_dispclk, pcie_table, valid_socclk_values, valid_dcefclk_values (allocated at :926-929, :954-957, :936-940, :942-946, :948-952, :964-967, :986-988, :1000-1002).

Nothing else frees them: vega10_hwmgr.c's backend teardown frees only hwmgr->backend and dyn_state.vddc_dep_on_dal_pwrl (vega10_hwmgr.c:787-790); phm_hwmgr_backend_fini doesn't touch pptable members.

Trigger cadence

  • /sys/class/drm/cardN/device/pp_table write (root only, S_IWUSR, amdgpu_pm.c:1007) β†’ pp_dpm_set_pp_table (amdgpu_powerplay.c:676) β†’ amd_powerplay_reset β†’ pptable_fini + pptable_init (hwmgr.c:261-281) β€” leaks once per write.
  • GPU unbind/rebind or module reload β€” leaks once per cycle.

Impact: unbounded kernel heap growth from a privileged trigger; each reload leaks 8 objects (tens of bytes to a few KB each). Low severity (DoS-by-memory-exhaustion needs sustained privileged action), CWE-401.

Verification

Runtime path needs an AMD Vega10 ASIC (absent on the audit guest β€” no 1002: PCI device, no /dev/dri). Source-certain: the alloc/free set difference above is mechanical. fix.diff adds the 8 missing kfree()+NULL pairs, git apply --check clean, and the patched file compiles with 0 syntax errors on the guest kernel toolchain (build.log).

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

not_testable at runtime (no AMD ASIC on guest); fix.diff compile-validated on the guest kernel toolchain (0 syntax errors).

fix.diff; build.log
↓ fix.diffDragonFly dfbsd 6.5-DEVELOPMENT #0 x86_64 (syntax validation only)

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md alloc-vs-free table (path:line for all 8 leaked allocations); fix.diff (git apply --check OK); build.log (0 syntax errors, guest kernel toolchain)

PoC changes

authored fresh this run (pass 2); no seed PoC

Verified recommended fix

free the 8 remaining subtable pointers in vega10_pp_tables_uninitialize (fix.diff)

Verdict

Source-certain kernel-heap leak: vega10_pp_tables_uninitialize (vega10_processpptables.c:1183-1228) frees only the original 9 allocations while the parser now creates ~17 β€” vdd_dep_on_socclk, vdd_dep_on_dcefclk, vdd_dep_on_pixclk, vdd_dep_on_phyclk, vdd_dep_on_dispclk, pcie_table, valid_socclk_values, valid_dcefclk_values (allocated at :926/:954/:936/:942/:948/:964/:986/:1000) are leaked on every teardown/re-init cycle, i.e. once per /sys pp_table write (root, amdgpu_pm.c:1007 -> amd_powerplay.c:676 -> hwmgr.c:261-281) and once per rebind/module-reload. Unbounded kernel-heap growth from a privileged trigger (CWE-401); Low severity. Runtime reproduction hardware-gated (no AMD ASIC on guest); fix.diff adds the 8 missing kfree pairs, git apply --check clean, patched file 0 syntax errors on the guest kernel toolchain.