⬢ DragonFlyBSD Kernel Audit
DF-5205 / analysis.txt
← back to finding ↓ download raw
DF-5205 annotated walkthrough — trinity_notify_message_to_smu() fail-open
Audit target: sys/dev/drm/radeon/trinity_smc.c (DragonFlyBSD pass 2, GLM 5.3)

[L30] static int trinity_notify_message_to_smu(struct radeon_device *rdev, u32 id)
      Only SMC transport in the file; all 10 exported wrappers route through it.
[L35] WREG32(SMC_MESSAGE_0, id);
      id is always a compile-time constant (ppsmc.h: PPSMC_MSG_* 0x100..0x12x)
      or, for the payload registers, a driver-derived level count. NOT user input.
[L36-40] for (i = 0; i < rdev->usec_timeout; i++) { if (RREG32(SMC_RESP_0) != 0) break; udelay(1); }
      usec_timeout = RADEON_MAX_USEC_TIMEOUT = 100000 (radeon.h:131; radeon_device.c:1300)
      -> up to 100 ms busy-wait. On timeout the loop simply exits; no error state kept.
[L41] v = RREG32(SMC_RESP_0);
      RAW 32-bit read. Trinity has NO SMC_RESP_MASK (cikd.h:431's 0xffff is CIK-only;
      the kv twin kv_smc.c:38,42 masks). Stray upper bits are indistinguishable here.
[L43] if (v != 1) {
[L44-46]     if (v == 0xFF) { DRM_ERROR("SMC failed to handle the message!"); return -EINVAL; }
[L47-49]     else if (v == 0xFE) { DRM_ERROR("Unknown SMC message!"); return -EINVAL; }
[L50]     }   <-- NO else. Falls through for v==0 (TIMEOUT) and v in 0x02..0xFD and any
               value with stray high bits (e.g. 0x00010001).
[L53] return 0;   <-- SUCCESS reported for every unhandled case. THE FAIL-OPEN.

Consumers (trinity_dpm.c):
  :59   trinity_dpm_bapm_enable          -> PPSMC_MSG_{Enable,Disable}BAPM
  :64   trinity_dpm_config               -> SMU_SCRATCH_0=0/1 + PPSMC_MSG_DPM_Config
  :74   trinity_dpm_force_state          -> SMU_SCRATCH_0=n + PPSMC_MSG_DPM_ForceState
  :81   trinity_dpm_n_levels_disabled    -> SMU_SCRATCH_0=n + PPSMC_MSG_DPM_N_LevelsDisabled
  :88   trinity_uvd_dpm_config           -> PPSMC_MSG_UVD_DPM_Config
  :93   trinity_dpm_no_forced_level      -> PPSMC_MSG_NoForcedLevel
  :98   trinity_dce_enable_voltage_adjustment -> PPSMC_MSG_DCE_{Allow,Remove}VoltageAdjustment
  :107  trinity_gfx_dynamic_mgpg_config  -> PPSMC_MSG_PG_SIMD_Config
Downstream: trinity_dpm_enable (trinity_dpm.c:1105-1132) returns 0 unconditionally
  at :1131 regardless of message outcomes -> radeon PM core marks DPM enabled on
  hardware that never acked. Same for the enable/disable/thermal paths at
  trinity_dpm.c:1099-1101, 1258-1273.

Family precedent: DF-5137 (radeon kv_smc.c:30-50, same shape but MASKED),
DF-5132 (amdgpu kv_smc.c). Trinity is strictly worse: unmasked response read.

Security assessment: reliability fail-open only. No memory-safety primitive, no
attacker-controlled data on the path, no unprivileged trigger. Info severity.

Fix (see fix.diff): catch-all `return -EINVAL` for any v != 1 outside the two
defined SMC error codes.