DF-4146 / fix.diff
--- a/dev/drm/radeon/trinity_dpm.c +++ b/dev/drm/radeon/trinity_dpm.c @@ -1747,11 +1747,21 @@ u8 frev, crev; u8 *power_state_offset; struct sumo_ps *ps; + u16 pp_size; if (!atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset)) return -EINVAL; + if (!atom_parse_data_header(mode_info->atom_context, index, &pp_size, + &frev, &crev, &data_offset)) + return -EINVAL; power_info = (union power_info *)((uint8_t*)mode_info->atom_context->bios + data_offset); + if ((u32)(le16_to_cpu(power_info->pplib.usStateArrayOffset) + 2) > pp_size || + (u32)(le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) + 3) > pp_size || + (u32)(le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) + 3) > pp_size) { + DRM_ERROR("invalid powerplay array offsets\n"); + return -EINVAL; + } state_array = (struct _StateArray *) ((uint8_t*)mode_info->atom_context->bios + data_offset + @@ -1771,6 +1781,17 @@ for (i = 0; i < state_array->ucNumEntries; i++) { u8 *idx; power_state = (union pplib_power_state *)power_state_offset; + if ((u32)(power_state_offset + 2 + power_state->v2.ucNumDPMLevels - + (u8 *)power_info) > pp_size) { + DRM_ERROR("state walk out of bounds at %d\n", i); + for (k = i - 1; k >= 0; k--) + kfree(rdev->pm.dpm.ps[k].ps_priv); + kfree(rdev->pm.dpm.ps); + rdev->pm.dpm.ps = NULL; + rdev->pm.dpm.boot_ps = NULL; + rdev->pm.dpm.uvd_ps = NULL; + return -EINVAL; + } 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]; |