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)
PoC verification
Evidence pack
findings/poc/DF-4858 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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 |
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
- Typo proof (source):
- rv730_dpm.c:180 clears
CLK_V_MASKin mpll_ss2, then :181 ORsCLK_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. - Executable proof (guest):
mclkss.creplicates :119-196 verbatim (dividers/SS entry as inputs; thepi->mclk_ssgate andradeon_atombios_get_asic_ss_infomatch are preconditions by construction). Baseline (run.log): - modereal(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. - modecrafted(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.korebuilt under -Werror: compile+link OK (radeon_fix_apply.log,radeon_module_build.log).- Harness fixed-build reruns both scenarios cleanly.
- Guest
/usr/srcreverted 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
fixedfixed: 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
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.
No comments yet.