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

smu_get_voltage_dependency_table_ppt_v1 copies VBIOS-controlled count records into callers' fixed entries[8] ODN tables β€” heap OOB write of struct smu7_hwmgr (up to 6916 attacker-controlled bytes)

Summary

The helper has no destination-size parameter and copies the raw VBIOS ucNumEntries (up to 255) x 28-byte records; the smu7 call sites cast fixed entries[MAX_REGULAR_DPM_NUMBER=8] tables embedded in the heap-allocated hwmgr struct - count>8 overflows into adjacent members, count=255 writes 6916 bytes past entries[7] and 6420 past the struct allocation with fully attacker-chosen record contents. Reachable at driver load with OverDrive enabled and via PP_OD_RESTORE_DEFAULT_TABLE. Novel vs DF-1166 (fires with <=8 distinct clocks - dedup site in bounds while the copy overflows) and DF-3703/1799 (different legs/aspects). Harness-verified on guest: 224 OOB bytes at count=16, 55/64 canaries smashed at 255; fix validated. Central-hub fix (clamp + capacity param) closes the whole family.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4665 Β· 11 files
FileTypeDescriptionSize
smu7_odn_overflow.c β€” 10.4 KB view raw
smu7_odn_overflow_patched.c β€” 5.2 KB view raw
build.sh β€” 187 B view raw
run.sh β€” 90 B view raw
build.log β€” 0 B ↓ download
run.log β€” 2.6 KB view raw
env.txt β€” 188 B view raw
VERDICT.md β€” 3.5 KB ↓ raw
fix.diff β€” 3.2 KB view raw
manifest.json β€” 1.3 KB view raw
verdict.json β€” 4.2 KB view raw
VERDICT.md
↓ download raw

DF-4665 β€” VERDICT

Status: reproduced (harness; no AMD GPU on the audit guest β€” methodology identical to DF-3683/DF-3686: verbatim kernel function + 1:1 struct layouts, canary-guarded adjacency, run on the DragonFly 6.5-DEVELOPMENT guest).

What was run

smu7_odn_overflow.c compiles the verbatim body of smu_get_voltage_dependency_table_ppt_v1 (smu_helper.c:675-699) against 1:1 copies of the kernel struct layouts (phm_ppt_v1_clock_voltage_dependency_record β€” 28 bytes, compiler-confirmed; phm_odn_clock_levels, smu7_odn_clock_voltage_dependency_table with entries[8], smu7_odn_dpm_table, and a struct smu7_hwmgr-prefix buffer with a 64-word canary region standing in for the members after odn_dpm_table).

Observations (run.log, guest cc 8.3, DF 6.5-DEVELOPMENT)

  1. count=16, 2 distinct clocks β€” the DF-1166 dedup loop appends only 2 dpm_levels (IN BOUNDS, the known finding does NOT fire), then the odn copy writes 16 Γ— 28 = 448 bytes into entries[8]: 224 bytes OOB, vdd_dependency_on_mclk.count corrupted from 0 to 102500 (a VBIOS clk value). Proves this bug fires on inputs the filed siblings do not cover.
  2. count=255, 2 distinct clocks β€” DF-1166 site still in bounds; odn copy writes 6916 bytes past entries[7], of which 6420 bytes past the end of the backend-shaped object; 55/64 canary words smashed; odn_mclk_min_limit, min_vddc, max_vddc all overwritten with attacker-record contents. On the real kernel this is a linear heap overflow of the kzalloc'd struct smu7_hwmgr with fully VBIOS-controlled data, running into whatever slab object follows.
  3. Control count=8 β€” no corruption (function behaves correctly when the source happens to be in range).
  4. Patched twin (fix.diff applied to the harness function, call site passes MAX_REGULAR_DPM_NUMBER): stored count clamped to 8, zero canary damage for count=16 and count=255 β€” fix validated.

Exploit chain (realistic ceiling)

Crafted VBIOS / VFIO pp_table write on an smu7 board (Tonga/Fiji/Polaris10/ VegaM) with OverDrive enabled β†’ at driver load smu7_setup_default_dpm_tables β†’ smu7_odn_initial_default_setting β†’ this copy β†’ controlled 28-byte-stride heap overflow inside/past struct smu7_hwmgr β†’ kernel heap corruption (adjacent slab objects; struct smu7_hwmgr is a several-KB kmalloc). Grooming the slab neighbour of the hwmgr backend could turn this into code execution; at minimum a deterministic kernel panic. The audit guest has no AMD GPU, so the chain is demonstrated at the primitive level (above), matching the methodology precedent of DF-3683.

Kernel references

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

fixed
baseline reproduced→ patch + rebuild →patched clean

Patched-twin harness (function carrying the fix.diff clamp, call site passing MAX_REGULAR_DPM_NUMBER) shows stored count clamped to 8, vdd_dependency_on_mclk intact, 0/64 canaries damaged for count=16 and count=255 β€” the out-of-bounds write is gone. Full kernel rebuild not performed: no AMD GPU exists on the audit guest, so the verbatim-function harness is the faithful validation surface (same methodology as DF-3683).

findings/poc/DF-4665/run.log 'patched twin' sections: 'FIX VALIDATED: no out-of-bounds writes with clamped copy' (count=16 and count=255).
↓ fix.diffper-fix-DF-4665

Confirmed kernel references

Detail

Exploit chain

crafted VBIOS / VFIO pp_table / root sysfs pp_table on smu7 board (Tonga/Fiji/Polaris10/VegaM) with od_enabled -> smu7_setup_default_dpm_tables:967 -> smu7_odn_initial_default_setting -> smu_get_voltage_dependency_table_ppt_v1(dep_sclk_table, &odn_table->vdd_dependency_on_sclk) -> linear heap overflow inside and past struct smu7_hwmgr with fully attacker-controlled 28-byte records (up to 6916 bytes past entries[7]) -> kernel heap corruption of adjacent slab objects; deterministic panic at minimum, potential code execution with slab grooming.

Evidence (decisive lines)

findings/poc/DF-4665/run.log: baseline count=255 section shows 'OOB bytes past entries[7] : 6916', 'past end of backend-like object: 6420', 'canary words ... smashed: 55/64', 'OOB-WRITE CONFIRMED'; count=16/2-distinct section shows DF-1166 site IN BOUNDS while vdd_dependency_on_mclk.count is corrupted (novelty vs DF-1166); patched-twin sections show 'FIX VALIDATED'.

PoC changes

Seed harness authored fresh for this finding (no prior seed): verbatim smu_helper.c:675-699 body + 1:1 struct layouts from hwmgr_ppt.h/hardwaremanager.h/smu7_hwmgr.h; canary-guarded struct-smu7_hwmgr-prefix buffer; DF-1166 dedup site replicated first to prove the new bug fires where the known one does not.

Verified recommended fix

Pass destination capacity (max_entries) to smu_get_voltage_dependency_table_ppt_v1 and clamp the copy; callers pass MAX_REGULAR_DPM_NUMBER.

Verdict

Harness-verified on the DragonFly 6.5-DEVELOPMENT guest using the verbatim kernel function and 1:1 struct layouts (no AMD GPU on the audit guest; methodology identical to DF-3683/DF-3686): smu_get_voltage_dependency_table_ppt_v1 has no destination-size parameter and copies allowed_dep_table->count (raw VBIOS ucNumEntries, up to 255) 28-byte records into callers' fixed entries[MAX_REGULAR_DPM_NUMBER=8] tables. The smu7 call path (smu7_odn_initial_default_setting, reached at driver load with OverDrive enabled and via PP_OD_RESTORE_DEFAULT_TABLE sysfs) overflows struct smu7_hwmgr: with count=16 and only 2 distinct clocks the already-filed DF-1166 dedup site stays in bounds while this copy writes 224 attacker-controlled bytes OOB (vdd_dependency_on_mclk.count corrupted to a VBIOS clk value); with count=255 it writes 6916 bytes past entries[7], 6420 past the backend-shaped allocation, 55/64 canary words smashed. Patched twin (fix.diff clamp) shows zero corruption.