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

vega10_get_sclk_od/get_mclk_od divide by zero when the golden top clock is 0 (crafted VBIOS) β€” world-readable sysfs trigger

Summary

vega10_setup_default_single_dpm_table appends the first dep entry unconditionally, so a GFXCLK/MCLK dependency table whose entries are all ulClk==0 yields golden_dpm_table top value 0; vega10_get_sclk_od/get_mclk_od then compute DIV_ROUND_UP(value*100, golden_value) -> integer #DE -> kernel panic. The pp_sclk_od sysfs attr is S_IRUGO, so with such a VBIOS ANY local user can trigger it via 'cat'. Crafted/blank-field VBIOS precondition keeps it Low.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-3707 Β· 10 files
FileTypeDescriptionSize
README.md β€” 1.6 KB ↓ raw
VERDICT.md β€” 1.7 KB ↓ raw
trigger_notes.c β€” 998 B view raw
build.sh β€” 86 B view raw
run.sh β€” 166 B view raw
run.log β€” 437 B view raw
env.txt β€” 848 B view raw
fix.diff β€” 892 B view raw
manifest.json β€” 925 B view raw
verdict.json β€” 2.2 KB view raw

DF-3707 β€” vega10_get_sclk_od / vega10_get_mclk_od divide by zero when the top golden clock is 0 (crafted VBIOS)

File: sys/dev/drm/amd/powerplay/hwmgr/vega10_hwmgr.c (pass 2).

Bug (:4529-4543, :4580-4594)

int value = sclk_table->dpm_levels[sclk_table->count - 1].value;         // :4535
int golden_value = golden_sclk_table->dpm_levels
        [golden_sclk_table->count - 1].value;                            // :4536-4537

value -= golden_value;
value = DIV_ROUND_UP(value * 100, golden_value);                          // :4540  <- /0

golden_sclk_table is the saved default dpm table; vega10_setup_default_single_dpm_table (:1200-1217) appends entry 0 unconditionally (i == 0 ||), so a GFXCLK dependency table whose entries are all ulClk == 0 (e.g. ucNumEntries == 1 with ulClk == 0) produces dpm_levels[0].value == 0, count == 1 β†’ golden_value == 0 β†’ integer division by zero β†’ kernel trap (#DE) β†’ panic. Identical shape for MCLK at :4586-4591.

Reachability (wider than the other vega10 findings)

The sysfs node is WORLD-READABLE: amdgpu_pm.c:1019-1020 static DEVICE_ATTR(pp_sclk_od, S_IRUGO | S_IWUSR, amdgpu_get_pp_sclk_od, ...) β€” cat /sys/class/drm/card0/device/pp_sclk_od by ANY local user calls get_sclk_od β†’ DIV_ROUND_UP β†’ #DE. Precondition is still the crafted-VBIOS (golden 0 clock), so overall severity Low.

Trigger (requires AMD Vega10 hardware)

VBIOS with a single GFXCLK dependency entry ulClk=0 (and matching MCLK for the mclk twin), then any local unprivileged cat .../pp_sclk_od.

PoC status

Guest virtio-only β†’ inconclusive, source-certain.

VERDICT.md
↓ download raw

DF-3707 VERDICT β€” get_sclk_od/get_mclk_od divide-by-zero

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

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

  1. vega10_setup_default_single_dpm_table (:1208-1215) appends the first dep entry unconditionally (i == 0 || ...), so a GFXCLK dep table with a single ulClk==0 entry yields dpm_levels[0].value==0, count==1 β€” no lower-bound clamp exists anywhere.
  2. golden_dpm_table is a memcpy of that table (:1417-1419).
  3. vega10_get_sclk_od :4535-4540: golden_value = dpm_levels[count-1].value == 0 β†’ DIV_ROUND_UP(value100, 0) β†’ (value100 + 0 - 1)/0 β†’ integer #DE β†’ kernel panic. vega10_get_mclk_od :4586-4591 identical.
  4. Trigger surface: amdgpu_pm.c:1019-1020 DEVICE_ATTR(pp_sclk_od, S_IRUGO|S_IWUSR, ...) β€” world-readable, so with the crafted VBIOS present ANY local user can panic the kernel (local DoS). vega10_dpm_get_sclk/get_mclk (:3659/:3681) also index [count-1] but count>=1 holds (asserted at :756/:761), so only the division is the fault.

Severity Low: requires the crafted/malformed VBIOS precondition; after that, unprivileged DoS.

Guest result

0 AMD PCI devices; amdgpu.ko never binds; pp_sclk_od absent. Lines confirmed in guest /usr/src (run.log). Verdict: inconclusive, source-certain.

Fix

fix.diff returns 0 when golden_value == 0 in both getters.

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-3707

Confirmed kernel references

Detail

Exploit chain

crafted VBIOS (single 0MHz GFXCLK/MCLK dep entry) -> unprivileged 'cat pp_sclk_od' -> DIV_ROUND_UP(x,0) #DE -> panic (DoS)

Evidence (decisive lines)

VERDICT.md; run.log (guest-src excerpt :4535-4540); trigger_notes.c (arithmetic demo); fix.diff

PoC changes

no runnable PoC possible (hardware-gated); documented chain + arithmetic

Verified recommended fix

Guard golden_value==0 and return 0 in both getters (fix.diff)

Verdict

Source-certain divide-by-zero: vega10_get_sclk_od (:4540) and vega10_get_mclk_od (:4591) divide by golden_dpm_table's top clock value, which is 0 when the crafted VBIOS dep table's first/max entry has ulClk==0 (setup_default_single_dpm_table :1209 appends entry 0 unconditionally); the pp_sclk_od sysfs attr is world-readable (amdgpu_pm.c:1019 S_IRUGO), so once such a VBIOS is present any local user can trigger the kernel #DE panic. Confidence 'likely' only because the full chain (0-clock golden table accepted through earlier stages) is argued from source, not executed. Not reproducible on the virtio-only audit guest (0 AMD PCI devices).