mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-24 14:51:43 -04:00
drm/amd/pm: Guard VBIOS AC timing table walk
Reject AC timing blocks with a stride smaller than a dword before walking VBIOS data. A zero stride can otherwise keep reg_data pinned on a nonmatching MEM_ID forever. Also bound the data-block and END marker reads by the returned VRAM_Info table size so malformed index/data sizes do not push the timing walk past the table. Signed-off-by: Xiang Liu <xiang.liu@amd.com> Reviewed-by: Hawking Zhang <Hawking.Zhang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
@@ -46,16 +46,22 @@ union voltage_object_info {
|
||||
static int atomctrl_retrieve_ac_timing(
|
||||
uint8_t index,
|
||||
ATOM_INIT_REG_BLOCK *reg_block,
|
||||
u8 *table_end,
|
||||
pp_atomctrl_mc_reg_table *table)
|
||||
{
|
||||
uint32_t i, j;
|
||||
u16 stride = le16_to_cpu(reg_block->usRegDataBlkSize);
|
||||
uint8_t tmem_id;
|
||||
ATOM_MEMORY_SETTING_DATA_BLOCK *reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
|
||||
((uint8_t *)reg_block + (2 * sizeof(uint16_t)) + le16_to_cpu(reg_block->usRegIndexTblSize));
|
||||
|
||||
uint8_t num_ranges = 0;
|
||||
|
||||
while (*(uint32_t *)reg_data != END_OF_REG_DATA_BLOCK &&
|
||||
if (stride < sizeof(uint32_t))
|
||||
return -EINVAL;
|
||||
|
||||
while ((uint8_t *)reg_data + sizeof(uint32_t) <= table_end &&
|
||||
*(uint32_t *)reg_data != END_OF_REG_DATA_BLOCK &&
|
||||
num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES) {
|
||||
tmem_id = (uint8_t)((*(uint32_t *)reg_data & MEM_ID_MASK) >> MEM_ID_SHIFT);
|
||||
|
||||
@@ -67,6 +73,10 @@ static int atomctrl_retrieve_ac_timing(
|
||||
for (i = 0, j = 1; i < table->last; i++) {
|
||||
if ((table->mc_reg_address[i].uc_pre_reg_data &
|
||||
LOW_NIBBLE_MASK) == DATA_FROM_TABLE) {
|
||||
if ((uint8_t *)reg_data +
|
||||
(j + 1) * sizeof(uint32_t) > table_end)
|
||||
return -EINVAL;
|
||||
|
||||
table->mc_reg_table_entry[num_ranges].mc_data[i] =
|
||||
(uint32_t)*((uint32_t *)reg_data + j);
|
||||
j++;
|
||||
@@ -81,11 +91,13 @@ static int atomctrl_retrieve_ac_timing(
|
||||
}
|
||||
|
||||
reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
|
||||
((uint8_t *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize)) ;
|
||||
((uint8_t *)reg_data + stride);
|
||||
}
|
||||
|
||||
PP_ASSERT_WITH_CODE((*(uint32_t *)reg_data == END_OF_REG_DATA_BLOCK),
|
||||
"Invalid VramInfo table.", return -1);
|
||||
if ((uint8_t *)reg_data + sizeof(uint32_t) > table_end ||
|
||||
*(uint32_t *)reg_data != END_OF_REG_DATA_BLOCK)
|
||||
return -EINVAL;
|
||||
|
||||
table->num_entries = num_ranges;
|
||||
|
||||
return 0;
|
||||
@@ -136,6 +148,7 @@ int atomctrl_initialize_mc_reg_table(
|
||||
{
|
||||
ATOM_VRAM_INFO_HEADER_V2_1 *vram_info;
|
||||
ATOM_INIT_REG_BLOCK *reg_block;
|
||||
u8 *table_end;
|
||||
int result = 0;
|
||||
u8 frev, crev;
|
||||
u16 size;
|
||||
@@ -157,6 +170,7 @@ int atomctrl_initialize_mc_reg_table(
|
||||
}
|
||||
|
||||
if (0 == result) {
|
||||
table_end = (uint8_t *)vram_info + size;
|
||||
reg_block = (ATOM_INIT_REG_BLOCK *)
|
||||
((uint8_t *)vram_info + le16_to_cpu(vram_info->usMemClkPatchTblOffset));
|
||||
result = atomctrl_set_mc_reg_address_table(reg_block, table);
|
||||
@@ -164,7 +178,7 @@ int atomctrl_initialize_mc_reg_table(
|
||||
|
||||
if (0 == result) {
|
||||
result = atomctrl_retrieve_ac_timing(module_index,
|
||||
reg_block, table);
|
||||
reg_block, table_end, table);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -177,6 +191,7 @@ int atomctrl_initialize_mc_reg_table_v2_2(
|
||||
{
|
||||
ATOM_VRAM_INFO_HEADER_V2_2 *vram_info;
|
||||
ATOM_INIT_REG_BLOCK *reg_block;
|
||||
u8 *table_end;
|
||||
int result = 0;
|
||||
u8 frev, crev;
|
||||
u16 size;
|
||||
@@ -198,6 +213,7 @@ int atomctrl_initialize_mc_reg_table_v2_2(
|
||||
}
|
||||
|
||||
if (0 == result) {
|
||||
table_end = (uint8_t *)vram_info + size;
|
||||
reg_block = (ATOM_INIT_REG_BLOCK *)
|
||||
((uint8_t *)vram_info + le16_to_cpu(vram_info->usMemClkPatchTblOffset));
|
||||
result = atomctrl_set_mc_reg_address_table(reg_block, table);
|
||||
@@ -205,7 +221,7 @@ int atomctrl_initialize_mc_reg_table_v2_2(
|
||||
|
||||
if (0 == result) {
|
||||
result = atomctrl_retrieve_ac_timing(module_index,
|
||||
reg_block, table);
|
||||
reg_block, table_end, table);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user