mirror of
https://github.com/torvalds/linux.git
synced 2026-09-20 09:40:02 +02:00
drm/amd/pm: Validate Tonga PowerPlay state array bounds
process_pptables_v1_0.c builds the Tonga state array pointer from usStateArrayOffset before checking that the table buffer covers the referenced data. A truncated PowerPlay table can therefore lead to out-of-bounds reads while validating the state array. Validate the fixed table size first, then check 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
c4a5160e3b
commit
1ac24df78c
|
|
@ -1152,15 +1152,17 @@ static int init_thermal_controller(
|
|||
* @powerplay_table: Pointer to the PowerPlay Table.
|
||||
* Exception: 2 if the powerplay table is incorrect.
|
||||
*/
|
||||
static int check_powerplay_tables(
|
||||
struct pp_hwmgr *hwmgr,
|
||||
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table
|
||||
)
|
||||
static int get_tonga_state_array(struct pp_hwmgr *hwmgr,
|
||||
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
|
||||
const ATOM_Tonga_State_Array **state_array)
|
||||
{
|
||||
const ATOM_Tonga_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_Tonga_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((ATOM_Tonga_TABLE_REVISION_TONGA <=
|
||||
powerplay_table->sHeader.ucTableFormatRevision),
|
||||
|
|
@ -1169,12 +1171,34 @@ static int check_powerplay_tables(
|
|||
"State table is not set!", return -1);
|
||||
PP_ASSERT_WITH_CODE((0 < powerplay_table->sHeader.usStructureSize),
|
||||
"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_Tonga_State_Array *)(((unsigned long)powerplay_table) +
|
||||
state_array_offset);
|
||||
PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries),
|
||||
"Invalid PowerPlay Table!", return -1);
|
||||
|
||||
state_array_size = struct_size(state_arrays, entries, 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_Tonga_POWERPLAYTABLE *powerplay_table)
|
||||
{
|
||||
const ATOM_Tonga_State_Array *state_arrays;
|
||||
|
||||
return get_tonga_state_array(hwmgr, powerplay_table, &state_arrays);
|
||||
}
|
||||
|
||||
static int pp_tables_v1_0_initialize(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
int result = 0;
|
||||
|
|
@ -1278,17 +1302,16 @@ const struct pp_table_func pptable_v1_0_funcs = {
|
|||
|
||||
int get_number_of_powerplay_table_entries_v1_0(struct pp_hwmgr *hwmgr)
|
||||
{
|
||||
ATOM_Tonga_State_Array const *state_arrays;
|
||||
const ATOM_Tonga_State_Array *state_arrays;
|
||||
const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr);
|
||||
int result;
|
||||
|
||||
PP_ASSERT_WITH_CODE((NULL != pp_table),
|
||||
"Missing PowerPlay Table!", return -1);
|
||||
PP_ASSERT_WITH_CODE((pp_table->sHeader.ucTableFormatRevision >=
|
||||
ATOM_Tonga_TABLE_REVISION_TONGA),
|
||||
"Incorrect PowerPlay table revision!", return -1);
|
||||
|
||||
state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) +
|
||||
le16_to_cpu(pp_table->usStateArrayOffset));
|
||||
result = get_tonga_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);
|
||||
}
|
||||
|
|
@ -1419,15 +1442,11 @@ int get_powerplay_table_entry_v1_0(struct pp_hwmgr *hwmgr,
|
|||
|
||||
if (pp_table->sHeader.ucTableFormatRevision >=
|
||||
ATOM_Tonga_TABLE_REVISION_TONGA) {
|
||||
state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) +
|
||||
le16_to_cpu(pp_table->usStateArrayOffset));
|
||||
|
||||
PP_ASSERT_WITH_CODE((0 < pp_table->usStateArrayOffset),
|
||||
"Invalid PowerPlay Table State Array Offset.", return -1);
|
||||
PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries),
|
||||
"Invalid PowerPlay Table State Array.", return -1);
|
||||
PP_ASSERT_WITH_CODE((entry_index <= state_arrays->ucNumEntries),
|
||||
"Invalid PowerPlay Table State Array Entry.", return -1);
|
||||
result = get_tonga_state_array(hwmgr, pp_table, &state_arrays);
|
||||
PP_ASSERT_WITH_CODE((result == 0),
|
||||
"Invalid PowerPlay Table State Array.", return result);
|
||||
PP_ASSERT_WITH_CODE((entry_index < state_arrays->ucNumEntries),
|
||||
"Invalid PowerPlay Table State Array Entry.", return -1);
|
||||
|
||||
state_entry = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
|
||||
ATOM_Tonga_State, entries,
|
||||
|
|
@ -1453,4 +1472,3 @@ int get_powerplay_table_entry_v1_0(struct pp_hwmgr *hwmgr,
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user