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

vega10 backend-init NULL-derefs optional pptable subtables (tdp/mm/lookup/dep tables) β€” missing-offset VBIOS panics the kernel (DF-3685 twin)

Summary

vega10_pp_tables_initialize NULL-initializes every subtable pointer and only parses one when its us*TableOffset is nonzero, returning SUCCESS with NULL pointers. vega10_hwmgr_backend_init then dereferences them before any NULL assert: vega10_set_features_platform_caps 'table_info->tdp_table->usClockStretchAmount', and vega10_patch_voltage_dependency_tables_with_lookup_table for all six dep tables plus the vddc/vddci/vddmem lookup entries and mm_table->count - all run BEFORE the only NULL asserts in the path. Crafted/malformed VBIOS (zero offsets) on a Vega10 -> deterministic NULL-deref panic at amdgpu attach: boot-time or hotplug local DoS.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3702 Β· 10 files
FileTypeDescriptionSize
README.md β€” 2.0 KB ↓ raw
VERDICT.md β€” 2.5 KB ↓ raw
trigger_notes.c β€” 1.5 KB view raw
build.sh β€” 134 B view raw
run.sh β€” 167 B view raw
run.log β€” 1.3 KB view raw
env.txt β€” 848 B view raw
fix.diff β€” 1.7 KB view raw
manifest.json β€” 1.1 KB view raw
verdict.json β€” 2.8 KB view raw

DF-3702 β€” vega10 backend-init dereferences optional pptable subtables without NULL checks (missing-offset VBIOS => NULL-deref panic)

File: sys/dev/drm/amd/powerplay/hwmgr/vega10_hwmgr.c (pass 2). smu7 checklist item (c) β€” DF-3685 vega10 twin.

Root cause

vega10_pp_tables_initialize (vega10_processpptables.c:905-922, verified in guest src) initializes every subtable pointer to NULL and only parses a subtable when its offset field in the ATOM powerplay table is non-zero; a zero offset leaves the pointer NULL and result == 0 (success). Later, vega10_hwmgr_backend_init dereferences those pointers unconditionally, BEFORE the only NULL asserts in the path (vega10_set_private_data_based_on_pptable :754-762 runs at :879):

  1. vega10_set_features_platform_caps :269 β€” table_info->tdp_table->usClockStretchAmount (called from backend_init :862). tdp_table is NULL when usPowerTuneTableOffset == 0.
  2. vega10_complete_dependency_tables (backend_init :876) β†’ vega10_patch_voltage_dependency_tables_with_lookup_table :635-686: - :658 vdt->count / :659 vdt->entries[entry_id] for all six dep tables (socclk/gfxclk/dcefclk/pixclk/dispclk/phyclk) β€” any NULL offset => deref, - :661 table_info->vddc_lookup_table->entries[...] β€” NULL when usVddcLookupTableOffset == 0, - :665 mm_table->count β€” NULL when usMMDependencyTableOffset == 0, - :677 vddci_lookup_table->entries[...], :680 vddmem_lookup_table->entries[...] β€” NULL when the respective offsets are 0 (loop over mclk entries runs unconditionally).

Trigger (requires AMD Vega10 hardware)

Craft VBIOS powerplay table: zero one or more of usPowerTuneTableOffset / us*DependencyTableOffset / usVddcLookupTableOffset / usVddciLookupTableOffset / usVddmemLookupTableOffset / usMMDependencyTableOffset (keep VDDC SVID2 atomfirmware objects intact so backend_init reaches :862). Driver attach β†’ immediate NULL-deref kernel panic (DoS at boot/hotplug).

PoC status

Guest virtio-only (env.txt) β€” amdgpu never binds; status inconclusive, source-certain.

VERDICT.md
↓ download raw

DF-3702 VERDICT β€” NULL subtable derefs at backend init

status: inconclusive (hardware-gated) β€” source-certain. reproduced=0 on audit guest.

Proof chain (all lines verified byte-identical in guest /usr/src, see run.log)

  1. Parser: vega10_processpptables.c:905-913 sets all 9 subtable pointers NULL; :916-922 (and the following identical guards for socclk/gfxclk/pix/phy/disp/dcef/mclk, pcie, hardlimit, and :1107-1128 for the three lookup tables) only populate a pointer when powerplay_table->us<Table>Offset != 0; offsets of 0 do NOT fail the parse.
  2. hwmgr_hw_init (hwmgr.c:222-229) calls pptable_init first, then backend_init.
  3. vega10_hwmgr_backend_init: - :862 vega10_set_features_platform_caps β†’ :269 table_info->tdp_table->usClockStretchAmount β€” NULL tdp_table (usPowerTuneTableOffset==0) β†’ NULL+offset deref β†’ panic. - :876 vega10_complete_dependency_tables β†’ :734 vega10_patch_voltage_dependency_tables_with_lookup_table β†’ :658 vdt->count for each of the 6 dep tables, :661 vddc_lookup_table, :665 mm_table, :677/:680 vddci/vddmem lookups β€” any of them NULL β†’ panic. This runs BEFORE :879 vega10_set_private_data_based_on_pptable, whose :754-762 asserts are the only NULL checks in the whole path (and even they only cover vdd_dep_on_socclk and vdd_dep_on_mclk).
  4. Contrast: the smu10/vega12 families and the later upstream vega10 code add explicit PP_ASSERT_WITH_CODE(table_info->x, ...) guards; this file has none for tdp/mm/lookup and relies on deref order.

Impact: crafted-VBIOS (flash / malicious eGPU / VFIO passthrough) β†’ deterministic kernel NULL-deref panic during amdgpu attach β†’ local DoS (boot-time or hotplug). Not memory corruption beyond the fault; severity Medium.

Guest result

0 AMD PCI devices; amdgpu.ko present but never binds; the panic cannot be produced on this guest. Cited lines confirmed present in guest /usr/src (run.log). Honest verdict: inconclusive (hardware-gated), source-certain.

Fix

fix.diff adds NULL guards (assert+skip / assert+return -EINVAL) at :269 and in the patch loop for each table, mirroring the set_private_data asserts.

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

fix.diff authored against read-only sys/ tree; no AMD hw on guest so no patched-kernel validation possible

fix.diff; run.log hardware gate
↓ fix.diffper-fix-DF-3702

Confirmed kernel references

Detail

Exploit chain

crafted VBIOS (missing PowerTune/dep/lookup/MM offsets) -> amdgpu attach -> vega10_hwmgr_backend_init :862/:876 -> NULL deref -> panic (DoS); no control-flow hijack demonstrated

Evidence (decisive lines)

VERDICT.md proof chain; run.log (guest-src excerpts :269,:658-661, parser NULL-init 905-922); trigger_notes.c (blob recipe); fix.diff

PoC changes

no runnable PoC possible (hardware-gated); documented the exact VBIOS offset fields to zero; verified cited lines in guest kernel source

Verified recommended fix

Add NULL guards before :269 and inside vega10_patch_voltage_dependency_tables_with_lookup_table (skip absent optional tables; -EINVAL for mandatory ones), mirroring :754-762 asserts

Verdict

Source-certain NULL-pointer dereference at driver attach (DF-3685 smu7 twin): vega10_pp_tables_initialize (vega10_processpptables.c:905-922,1107-1128) leaves optional subtable pointers NULL when the corresponding us*TableOffset is 0 and still returns success; vega10_hwmgr_backend_init then dereferences table_info->tdp_table at vega10_hwmgr.c:269 (via :862) and the six dep tables + vddc/vddci/vddmem lookup tables + mm table at :658/:661/:665/:677/:680 (via :876->:734), all before the only NULL asserts in the path (:754-762, reached at :879). Crafted-VBIOS Vega10 -> deterministic kernel panic at attach (DoS). Not reproducible on the audit guest (0 AMD PCI devices; amdgpu.ko present but never binds); cited lines verified byte-identical in guest /usr/src.