mirror of
https://github.com/torvalds/linux.git
synced 2026-09-26 10:02:02 +02:00
drm/amd/pm: Validate Vega hwmgr PowerPlay table bounds
The Vega hwmgr PowerPlay table parsers read fixed table fields, state array entries, or SMC PPT fields before validating that the VBIOS table buffer covers those structures. A truncated table can therefore lead to out-of-bounds reads during hwmgr initialization. Reject tables smaller than the fixed PowerPlay table. For Vega10, also validate the state array offset and entry range before dereferencing the state array. Signed-off-by: Yang Wang <kevinyang.wang@amd.com> Reviewed-by: Hawking Zhang <Hawking.Zhang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
1ac24df78c
commit
3a8d8e0b7f
|
|
@ -63,14 +63,17 @@ static const void *get_powerplay_table(struct pp_hwmgr *hwmgr)
|
|||
return table_address;
|
||||
}
|
||||
|
||||
static int check_powerplay_tables(
|
||||
struct pp_hwmgr *hwmgr,
|
||||
const ATOM_Vega10_POWERPLAYTABLE *powerplay_table)
|
||||
static int get_vega10_state_array(struct pp_hwmgr *hwmgr,
|
||||
const ATOM_Vega10_POWERPLAYTABLE *powerplay_table,
|
||||
const ATOM_Vega10_State_Array **state_array)
|
||||
{
|
||||
const ATOM_Vega10_State_Array *state_arrays;
|
||||
u16 state_array_offset;
|
||||
size_t state_array_size;
|
||||
size_t table_size = hwmgr->soft_pp_table_size;
|
||||
|
||||
state_arrays = (ATOM_Vega10_State_Array *)(((unsigned long)powerplay_table) +
|
||||
le16_to_cpu(powerplay_table->usStateArrayOffset));
|
||||
PP_ASSERT_WITH_CODE((table_size >= sizeof(*powerplay_table)),
|
||||
"Invalid PowerPlay Table!", return -1);
|
||||
|
||||
PP_ASSERT_WITH_CODE((powerplay_table->sHeader.format_revision >=
|
||||
ATOM_Vega10_TABLE_REVISION_VEGA10),
|
||||
|
|
@ -79,12 +82,34 @@ static int check_powerplay_tables(
|
|||
"State table is not set!", return -1);
|
||||
PP_ASSERT_WITH_CODE(powerplay_table->sHeader.structuresize > 0,
|
||||
"Invalid PowerPlay Table!", return -1);
|
||||
|
||||
state_array_offset = le16_to_cpu(powerplay_table->usStateArrayOffset);
|
||||
PP_ASSERT_WITH_CODE((state_array_offset <=
|
||||
table_size - sizeof(*state_arrays)),
|
||||
"Invalid PowerPlay Table!", return -1);
|
||||
|
||||
state_arrays = (ATOM_Vega10_State_Array *)(((unsigned long)powerplay_table) +
|
||||
state_array_offset);
|
||||
PP_ASSERT_WITH_CODE(state_arrays->ucNumEntries > 0,
|
||||
"Invalid PowerPlay Table!", return -1);
|
||||
|
||||
state_array_size = struct_size(state_arrays, states, state_arrays->ucNumEntries);
|
||||
PP_ASSERT_WITH_CODE((state_array_size <= table_size - state_array_offset),
|
||||
"Invalid PowerPlay Table!", return -1);
|
||||
|
||||
*state_array = state_arrays;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_powerplay_tables(struct pp_hwmgr *hwmgr,
|
||||
const ATOM_Vega10_POWERPLAYTABLE *powerplay_table)
|
||||
{
|
||||
const ATOM_Vega10_State_Array *state_arrays;
|
||||
|
||||
return get_vega10_state_array(hwmgr, powerplay_table, &state_arrays);
|
||||
}
|
||||
|
||||
static int set_platform_caps(struct pp_hwmgr *hwmgr, uint32_t powerplay_caps)
|
||||
{
|
||||
set_hw_cap(
|
||||
|
|
@ -1313,15 +1338,14 @@ int vega10_get_number_of_powerplay_table_entries(struct pp_hwmgr *hwmgr)
|
|||
{
|
||||
const ATOM_Vega10_State_Array *state_arrays;
|
||||
const ATOM_Vega10_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr);
|
||||
int result;
|
||||
|
||||
PP_ASSERT_WITH_CODE((pp_table != NULL),
|
||||
"Missing PowerPlay Table!", return -1);
|
||||
PP_ASSERT_WITH_CODE((pp_table->sHeader.format_revision >=
|
||||
ATOM_Vega10_TABLE_REVISION_VEGA10),
|
||||
"Incorrect PowerPlay table revision!", return -1);
|
||||
|
||||
state_arrays = (ATOM_Vega10_State_Array *)(((unsigned long)pp_table) +
|
||||
le16_to_cpu(pp_table->usStateArrayOffset));
|
||||
result = get_vega10_state_array(hwmgr, pp_table, &state_arrays);
|
||||
PP_ASSERT_WITH_CODE((result == 0),
|
||||
"Invalid PowerPlay Table State Array.", return result);
|
||||
|
||||
return (uint32_t)(state_arrays->ucNumEntries);
|
||||
}
|
||||
|
|
@ -1372,17 +1396,11 @@ int vega10_get_powerplay_table_entry(struct pp_hwmgr *hwmgr,
|
|||
|
||||
if (pp_table->sHeader.format_revision >=
|
||||
ATOM_Vega10_TABLE_REVISION_VEGA10) {
|
||||
state_arrays = (ATOM_Vega10_State_Array *)
|
||||
(((unsigned long)pp_table) +
|
||||
le16_to_cpu(pp_table->usStateArrayOffset));
|
||||
|
||||
PP_ASSERT_WITH_CODE(pp_table->usStateArrayOffset > 0,
|
||||
"Invalid PowerPlay Table State Array Offset.",
|
||||
return -1);
|
||||
PP_ASSERT_WITH_CODE(state_arrays->ucNumEntries > 0,
|
||||
result = get_vega10_state_array(hwmgr, pp_table, &state_arrays);
|
||||
PP_ASSERT_WITH_CODE((result == 0),
|
||||
"Invalid PowerPlay Table State Array.",
|
||||
return -1);
|
||||
PP_ASSERT_WITH_CODE((entry_index <= state_arrays->ucNumEntries),
|
||||
return result);
|
||||
PP_ASSERT_WITH_CODE((entry_index < state_arrays->ucNumEntries),
|
||||
"Invalid PowerPlay Table State Array Entry.",
|
||||
return -1);
|
||||
|
||||
|
|
@ -1424,4 +1442,3 @@ int vega10_baco_set_cap(struct pp_hwmgr *hwmgr)
|
|||
PHM_PlatformCaps_BACO);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,13 @@ static int check_powerplay_tables(
|
|||
struct pp_hwmgr *hwmgr,
|
||||
const ATOM_Vega12_POWERPLAYTABLE *powerplay_table)
|
||||
{
|
||||
size_t smc_pptable_size =
|
||||
offsetofend(ATOM_Vega12_POWERPLAYTABLE, smcPPTable);
|
||||
size_t table_size = hwmgr->soft_pp_table_size;
|
||||
|
||||
PP_ASSERT_WITH_CODE((table_size >= smc_pptable_size),
|
||||
"Invalid PowerPlay Table!", return -1);
|
||||
|
||||
PP_ASSERT_WITH_CODE((powerplay_table->sHeader.format_revision >=
|
||||
ATOM_VEGA12_TABLE_REVISION_VEGA12),
|
||||
"Unsupported PPTable format!", return -1);
|
||||
|
|
|
|||
|
|
@ -66,6 +66,13 @@ static int check_powerplay_tables(
|
|||
struct pp_hwmgr *hwmgr,
|
||||
const ATOM_Vega20_POWERPLAYTABLE *powerplay_table)
|
||||
{
|
||||
size_t smc_pptable_size =
|
||||
offsetofend(ATOM_Vega20_POWERPLAYTABLE, smcPPTable);
|
||||
size_t table_size = hwmgr->soft_pp_table_size;
|
||||
|
||||
PP_ASSERT_WITH_CODE((table_size >= smc_pptable_size),
|
||||
"Invalid PowerPlay Table!", return -1);
|
||||
|
||||
PP_ASSERT_WITH_CODE((powerplay_table->sHeader.format_revision >=
|
||||
ATOM_VEGA20_TABLE_REVISION_VEGA20),
|
||||
"Unsupported PPTable format!", return -1);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user