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

Wrong-variable store mpll_ss |= CLK_V(clk_v) corrupts memory-clock spread-spectrum programming on RV730 (CLK_V lost from mpll_ss2, CLK_S clobbered) β€” typo also present in upstream Linux

Summary

CLK_V_MASK is cleared in mpll_ss2 but CLK_V(clk_v) is OR'd into mpll_ss - SSEN runs mclk SS with zero depth and clk_v's low bits clobber the just-programmed CLK_S field (realistic 2->58; crafted 1->839), higher bits spilling into other fields. Fires on every mclk level population on real SS-enabled RV730 boards. Provable typo (the same file's sclk twin and rv740 program the paired word correctly; upstream Linux carries it too - report upstream). Verbatim-replica harness verified baseline corruption vs exact fixed fields; one-line fix compiled into radeon.ko -Werror.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4858 Β· 8 files
FileTypeDescriptionSize
mclkss.c trigger verbatim userland replica of rv730_populate_mclk_value SS block (rv730_dpm.c:119-196) 7.4 KB view raw
build.sh build-script cc -O2 -Wall; second binary with -DFIX_DF4858 65 B view raw
run.sh run-script baseline real/crafted + fixed real/crafted 183 B view raw
build.log build-log clean -Wall build output 254 B view raw
run.log run-log decisive guest run: V1/V2 violations baseline, exact fields fixed 1.7 KB view raw
fix.diff suggested-fix one-line fix: mpll_ss2 |= CLK_V(clk_v) 216 B view raw
VERDICT.md verdict full narrative incl. upstream-Linux cross-check 3.2 KB ↓ raw
env.txt env guest uname/cc/source-hash 832 B view raw
VERDICT.md verdict full narrative incl. upstream-Linux cross-check
↓ download raw

DF-4858 VERDICT

Finding: wrong-variable store at sys/dev/drm/radeon/rv730_dpm.c:181 β€” mpll_ss |= CLK_V(clk_v); where the cleared-at-:180 target was mpll_ss2. Corrupts the memory-clock spread-spectrum register pair programmed into the SMC state table.

Status: REPRODUCED (logic level, verbatim-replica harness on the audit guest; kernel-level trigger hardware-gated β€” guest has no Radeon GPU; methodology per DF-4492 precedent for this driver family).

Impact: none at the kernel-memory level (fixed-size register-word arithmetic, no OOB, no pointer involvement) β€” the impact is hardware misprogramming: SSEN-enabled mclk SS with zero depth (CLK_V never lands in mpll_ss2) plus CLK_S field (bits 4-15) clobbered by clk_v's low bits, on real SS-enabled RV730 boards on every DPM mclk population. Ceiling: mclk instability / GPU wedge (functional DoS of the graphics stack). No escalation chain exists for this class.

How it was proven

  1. Typo proof (source): - rv730_dpm.c:180 clears CLK_V_MASK in mpll_ss2, then :181 ORs CLK_V(clk_v) into mpll_ss. - Same-file sclk twin (rv730_dpm.c:104-105) does it correctly: cg_spll_spread_spectrum_2 &= ~CLK_V_MASK; cg_spll_spread_spectrum_2 |= CLK_V(clk_v); - Same-tree rv740_dpm.c:262-266 pairs each mask with its own word. - Upstream Linux master rv730_dpm.c carries the identical mclk typo (checked against torvalds/linux); DFly inherited it in the drm port.
  2. Executable proof (guest): mclkss.c replicates :119-196 verbatim (dividers/SS entry as inputs; the pi->mclk_ss gate and radeon_atombios_get_asic_ss_info match are preconditions by construction). Baseline (run.log): - mode real (rate=3000, percentage=20000, fb_div=932, ref 2700): clk_s=2 clk_v=932 β†’ mpll_ss CLK_S field becomes 58 (2 | (932>>4)&0xfff), mpll_ss2 CLK_V field 0 β€” SMC would run SS at depth 0 with corrupted step; VIOLATIONS V1+V2, exit=98. - mode crafted (percentage=65535, fb_div=2047): CLK_S 1β†’839, exit=98. - Fixed build (-DFIX_DF4858): fields exact (CLK_S=2/1, CLK_V=932/13415 in mpll_ss2), exit=0.

Fix validation

  • fix.diff (one line, mpll_ss2 |= CLK_V(clk_v);) applied to the guest /usr/src (with DF-4857's guard); radeon.ko rebuilt under -Werror: compile+link OK (radeon_fix_apply.log, radeon_module_build.log).
  • Harness fixed-build reruns both scenarios cleanly.
  • Guest /usr/src reverted afterwards (md5 verified pristine).

Notes

  • DF-1937 (ss.rate==0/clk_s==0 div0 at :97/:173) is the neighboring code in the same block and is NOT re-reported here; this finding is solely the wrong-destination store of the already-computed clk_v.
  • vco_freq = memory_clock * post_divider (:168) can wrap u32 on crafted mclk β€” only used as the SS-table match key (worst case: wrong entry selected) β€” noted, not filed.

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

fixed: fix.diff (one-line mpll_ss2 target) applied to guest /usr/src together with DF-4857's guard; radeon.ko rebuilt under -Werror with compile+link OK (radeon_fix_apply.log / radeon_module_build.log); harness baseline shows V1+V2 violations (exit=98) vs harness_fixed with exact CLK_S/CLK_V fields (exit=0) on both scenarios; guest source then reverted (md5 re-verified pristine).

fix.diff; run.log (fixed sections); radeon_fix_apply.log; radeon_module_build.log; VERDICT.md
↓ fix.diffper-fix-DF-4858

Confirmed kernel references

Detail

Evidence (decisive lines)

run.log (decisive: baseline real -> 'mpll_ss=0x000003a5 (CLK_S field=58, expected 2) [V1 CLOBBERED]', 'mpll_ss2=0x08000000 (CLK_V field=0, expected 932) [V2 LOST] [V3 SSEN with zero depth]', exit=98; baseline crafted -> CLK_S 1->839, exit=98; fixed -> fields exact, exit=0); mclkss.c (verbatim replica); radeon_fix_apply.log + radeon_module_build.log (shared fix build with DF-4857); VERDICT.md (incl. upstream cross-check)

PoC changes

Authored fresh (no seed): verbatim replica of the mclk SS block with pi/rdev replaced by provided inputs (mclk_ss gate and radeon_atombios_get_asic_ss_info match are preconditions by construction). One build iteration: unused-variable warning for post_divider silenced by keeping the vco_freq SS-match-key line from the original (:168), making the replica more faithful. Upstream Linux master checked for the same line (typo present there too).

Verified recommended fix

One line: change rv730_dpm.c:181 from 'mpll_ss |= CLK_V(clk_v);' to 'mpll_ss2 |= CLK_V(clk_v);' so the memory-clock spread-spectrum depth lands in the register word whose field was cleared at :180 (mirrors the sclk block at :104-105 and rv740_dpm.c:262-266).

Verdict

Reproduced at logic level with a verbatim userland replica of the rv730_populate_mclk_value SS block (rv730_dpm.c:119-196, rv730d.h macros verbatim) run on the audit guest; the kernel-level trigger is hardware-gated (no RV730 GPU in the guest). rv730_dpm.c:181 stores CLK_V(clk_v) into mpll_ss after clearing CLK_V_MASK in mpll_ss2 (:180) - a provable wrong-variable typo: the sclk twin block in the same file (:104-105) and rv740_dpm.c:262-266 both program the paired word correctly, and upstream Linux master carries the identical inherited typo. Baseline replica: the CLK_S field (bits 4-15, programmed at :177) is clobbered by clk_v's low bits (2->58 realistic, 1->839 crafted) while mpll_ss2's CLK_V field stays 0 - the SMC state table runs mclk spread spectrum with SSEN set, zero depth and a corrupted step on every mclk level population on SS-enabled RV730 boards (no crafted input required). Impact ceiling is hardware misprogramming (mclk instability / GPU wedge, functional DoS of the graphics stack): fixed-size register words only, no OOB, no pointer involvement, no kernel memory corruption, no escalation chain. Fix validated: the one-line fix.diff applied to guest /usr/src (with DF-4857's guard), radeon.ko rebuilt under -Werror (link OK), harness_fixed produces exact CLK_S/CLK_V fields for both scenarios.