diff --git a/sys/dev/drm/radeon/radeon_atombios.c b/sys/dev/drm/radeon/radeon_atombios.c --- a/sys/dev/drm/radeon/radeon_atombios.c +++ b/sys/dev/drm/radeon/radeon_atombios.c @@ -2701,11 +2701,11 @@ non_clock_array_index = power_state->v2.nonClockInfoIndex; non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) &non_clock_info_array->nonClockInfo[non_clock_array_index]; - rdev->pm.power_state[i].clock_info = kzalloc(sizeof(struct radeon_pm_clock_info) * + rdev->pm.power_state[state_index].clock_info = kzalloc(sizeof(struct radeon_pm_clock_info) * (power_state->v2.ucNumDPMLevels ? power_state->v2.ucNumDPMLevels : 1), GFP_KERNEL); - if (!rdev->pm.power_state[i].clock_info) + if (!rdev->pm.power_state[state_index].clock_info) return state_index; if (power_state->v2.ucNumDPMLevels) { for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) { @@ -2730,6 +2730,17 @@ radeon_atombios_parse_pplib_non_clock_info(rdev, state_index, mode_index, non_clock_info); state_index++; + } else { + /* DF-1198: this state produced no valid clock modes, so it is not + * compacted into the power_state[] array. Free its clock_info so + * the state_index slot can be reused by the next iteration. + * Previously clock_info was allocated against index i while every + * write used state_index; once state_index lagged i (a prior state + * with zero valid modes), the next state's writes landed in a + * buffer sized for a different state -> heap overflow. Allocating + * and writing against the same index closes the overflow. */ + kfree(rdev->pm.power_state[state_index].clock_info); + rdev->pm.power_state[state_index].clock_info = NULL; } power_state_offset += 2 + power_state->v2.ucNumDPMLevels; }