smu9_send_msg_to_smc/_with_parameter return 0 on SMC failure β vacuous caller error guards and stale smu9_get_argument() data flow into Vega10/12 powerplay decisions
Summary
Both senders log failure then unconditionally return 0 - every caller guard (PP_ASSERT_WITH_CODE, ==0-success tests) is dead, and get_argument serves the PREVIOUS message's C2PMSG_82 (only the response register is zeroed): stale if-version, stale feature bitmaps, stale SMU tables. Hardware-fault-gated; no memory-unsafe sink (memcpy sizes driver-fixed). Verbatim upstream port. Propagate-the-failure fix (caller-compatible, git-apply verified).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-5181 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 3.1 KB | β raw | |
| VERDICT.md | β | 3.7 KB | β raw | |
| fix.diff | β | 753 B | view raw | |
| manifest.json | β | 1.3 KB | view raw | |
| verdict.json | β | 3.6 KB | view raw |
DF-5181 β smu9 SMC-message failures are swallowed (return 0), vacating caller error guards and feeding stale smu9_get_argument() data into Vega10/12 powerplay
File: sys/dev/drm/amd/powerplay/smumgr/smu9_smumgr.c (155 LOC)
Class: CWE-252 (Unchecked Return Code) / CWE-754 (Improper Check for Exceptional Conditions)
Severity: Low Β· Confidence: certain Β· Bucket: base:drm (vendored-parity with upstream Linux)
What the code does
smu9_send_msg_to_smc() (smu9_smumgr.c:101-117) and
smu9_send_msg_to_smc_with_parameter() (smu9_smumgr.c:128-147) both detect
SMC failure β ret = smu9_wait_for_response(hwmgr); if (ret != 1) β but only
pr_err() it and then unconditionally return 0 (:116, :146).
The wait itself is bounded (phm_wait_for_register_unequal,
smu_helper.c:151-173, hwmgr->usec_timeout = AMD_MAX_USEC_TIMEOUT = 200 ms,
hwmgr.c:85) so there is no hang; each wedged message burns two full timeouts
(pre-send drain at :106/:134 + real wait at :112/:142).
Consequence (why the return value matters)
Callers were written expecting a propagated error:
vega10_smumgr.c:147-150:PP_ASSERT_WITH_CODE(!smu9_send_msg_to_smc(hwmgr, PPSMC_MSG_GetDriverIfVersion), "Attempt to get SMC IF Version Number Failed!", return -EINVAL)β with the always-0 return this guard can NEVER fire; :151 then readssmc_driver_if_version = smu9_get_argument(hwmgr)from C2PMSG_82, which was not overwritten by the failed message (only the response reg C2PMSG_90 is zeroed at :108/:136) β stale value flows into the version check at :160.vega12_smumgr.c:52-57writes the condition explicitly assmu9_send_msg_to_smc_with_parameter(...) == 0with the message "Attempt to Set Dram Addr High Failed!" β dead guard today.vega10_smumgr.c:47-58(vega10_copy_table_from_smc): three unchecked sends (SetDriverDramAddrHigh/Low + TransferTableSmu2Dram) followed bymemcpy(table, priv->smu_tables.entry[table_id].table, ...size)β on a failed transfer the driver memcpy's the previous contents of the driver-side buffer and the powerplay state machine consumes stale table data.vega10_smumgr.c:107-108: stalefeatures_enabledbitmap drivesvega10_is_dpm_running()(:113-123) decisions.
No memory-unsafe sink was found: all table-copy sizes are driver-fixed at
allocation (vega10_smumgr.c:45-46, :57-58), never derived from
smu9_get_argument(). Impact ceiling is wrong power/clock/DPM decisions from
stale SMU state.
Reproduce
Requires Vega10/Vega12 silicon with a hung/mismatched SMC firmware β not
testable on the audit QEMU guest (virt hardware, no AMD dGPU). The defect is
a source-semantics property fully demonstrated by citation above; no runtime
verification was attempted (status untested). Fix validation likewise
not_testable β see VERDICT.md.
Fix
fix.diff in this directory: propagate return (ret == 1) ? 0 : -EIO; in both
send functions. Caller-compatible (vega10/vega12 guards already treat 0 as
success). Matches the direction upstream Linux eventually needs; this file is a
verbatim port of upstream smu9_smumgr.c, so the fix owner is upstream
drm-amd.
VERDICT β DF-5181
- Finding: smu9 SMC-message failures swallowed (
return 0), vacuous caller guards, stalesmu9_get_argument()consumption. - File:
sys/dev/drm/amd/powerplay/smumgr/smu9_smumgr.c - PoC status: untested (Phase V skipped per reviewer contract: Low severity, hardware-fault-gated). reproduced = false, impact = none.
- Confidence: certain β the defect is unconditional in the source and the vacuous-guard consequence is directly readable in the callers.
Why skipped (honest classification)
The QEMU/KVM audit guest has no AMD Vega10/Vega12 dGPU; the amdgpu powerplay
path for smu9 (hwmgr->smumgr_funcs wired by vega10_smumgr.c:353-358 /
vega12_smumgr.c:372-377) cannot be instantiated, so neither the baseline nor a
patched kernel can be exercised on it. The trigger additionally requires the
SMC firmware to fail/time out β a hardware/firmware fault state, not an
attacker-injectable input. There is no memory-corruption primitive to develop:
every table-transfer memcpy uses driver-fixed sizes allocated at init
(vega10_smumgr.c:45-46 β :57-58); smu9_get_argument() output only reaches
version/feature logic (vega10_smumgr.c:151,160; :107-108 β :113-123).
Root cause (path:line)
smu9_smumgr.c:112-116and:142-146: failure detected (ret != 1), logged, thenreturn 0unconditionally.smu9_wait_for_response(:61-76): bounded wait β no hang possible (smu_helper.c:161-172,usec_timeout= 200 ms, hwmgr.c:85, amd_shared.h:29). Two full timeouts burned per failed message (pre-send drain:106/:134+ real wait:112/:142).- Argument staleness:
:108/:136zero only the response register (C2PMSG_90); C2PMSG_82 (read raw bysmu9_get_argument,:150-155) retains the previous message's value.
Caller-side proof the guards are vacuous
pp_debug.h:37-43:PP_ASSERT_WITH_CODE(cond, ...)fires iff!(cond).vega10_smumgr.c:147-150: cond =!smu9_send_msg_to_smc(...)=!0= always true β the "Attempt to get SMC IF Version Number Failed!" branch is unreachable;:151consumes stale C2PMSG_82.vega12_smumgr.c:52-57: cond written assmu9_send_msg_to_smc_with_parameter(...) == 0with failure messages β always true today, i.e. dead error handling (proving callers expect a propagated error).vega10_smumgr.c:47-58: zero checks at all before the tablememcpy.
Impact ceiling
Robustness/logic only: on an SMC that is wedged or firmware-mismatched, the
Vega10/12 driver proceeds as if messages succeeded β stale driver-if version,
stale enabled-feature bitmaps (vega10_is_dpm_running), stale SMU table
contents consumed by hwmgr. Wrong clocks/power gating; no kernel memory
safety violation, no unprivileged-local trigger (message paths run at
init/suspend/power-state transitions; no user data reaches C2PMSG_66/82 here).
Upstream parity: file is a verbatim port of Linux
drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.c β upstream carries the
identical defect; fix owner upstream.
Fix validation
fix_status = not_testable (no Vega silicon on the audit guest; fix is a two-line return-value change whose caller compatibility is verifiable by inspection β every in-tree caller treats 0 as success: vega10_smumgr.c:147, vega12_smumgr.c:52-57,63-68 and the function-pointer table at vega10_smumgr.c:353-354 / vega12_smumgr.c:372-373).
fix.diff authored against the read-only sys/ tree; never applied there.
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_testablefix.diff authored (two return-value changes + comments) against the read-only sys/ tree. Baseline/patched runtime comparison impossible on the audit guest (no Vega silicon); caller compatibility verified by inspection: all in-tree call sites treat 0 as success (vega10_smumgr.c:147, vega12_smumgr.c:52-57, function tables vega10_smumgr.c:353-354 / vega12_smumgr.c:372-373).
findings/poc/DF-5181/fix.diff (git-apply-able unified diff, generated via diff -u from the pristine file; hunk headers @@ -113,7 and @@ -143,7 match the audited tree).
Confirmed kernel references
- sys/dev/drm/amd/powerplay/smumgr/smu9_smumgr.c:112
- sys/dev/drm/amd/powerplay/smumgr/smu9_smumgr.c:116
- sys/dev/drm/amd/powerplay/smumgr/smu9_smumgr.c:142
- sys/dev/drm/amd/powerplay/smumgr/smu9_smumgr.c:146
- sys/dev/drm/amd/powerplay/smumgr/smu9_smumgr.c:150
- sys/dev/drm/amd/powerplay/smumgr/vega10_smumgr.c:47
- sys/dev/drm/amd/powerplay/smumgr/vega10_smumgr.c:107
- sys/dev/drm/amd/powerplay/smumgr/vega10_smumgr.c:147
- sys/dev/drm/amd/powerplay/smumgr/vega12_smumgr.c:52
- sys/dev/drm/amd/powerplay/hwmgr/smu_helper.c:161
- sys/dev/drm/amd/powerplay/hwmgr/hwmgr.c:85
Detail
Evidence (decisive lines)
findings/poc/DF-5181/VERDICT.md (caller-side vacuous-guard proof with pp_debug.h:37-43 polarity); README.md; fix.diff. Decisive lines: smu9_smumgr.c:113-116 and :143-146 (log-then-return-0), vega10_smumgr.c:147-151, vega12_smumgr.c:52-57.
PoC changes
No PoC authored: finding is a source-semantics defect (unconditional return 0) fully demonstrated by citation; guest lacks AMD Vega silicon so no runtime PoC is possible.
Verified recommended fix
Propagate SMC failure: return (ret == 1) ? 0 : -EIO; in both smu9_send_msg_to_smc and smu9_send_msg_to_smc_with_parameter (caller-compatible; vega10/vega12 guards already expect 0 == success).
Verdict
smu9_send_msg_to_smc (smu9_smumgr.c:101-117) and smu9_send_msg_to_smc_with_parameter (:128-147) detect SMC failure (ret != 1 from the bounded smu9_wait_for_response) but unconditionally return 0 at :116/:146, so every in-tree caller guard is vacuous (vega10_smumgr.c:147-150 PP_ASSERT_WITH_CODE(!send) can never fire; vega12_smumgr.c:52-57 tests ==0 as success) and smu9_get_argument() (:150-155) serves stale C2PMSG_82 content into version/feature/table logic (vega10_smumgr.c:151,160 / :107-108->:113-123 / :47-58). No memory-unsafe sink: table memcpy sizes are driver-fixed (vega10_smumgr.c:45-46,57-58); waits are bounded (smu_helper.c:161-172, usec_timeout=200ms hwmgr.c:85). Phase V skipped per contract (Low, hardware-fault-gated, vendored parity with upstream Linux which carries the identical defect).
No comments yet.