diff options
| author | Yang Wang <kevinyang.wang@amd.com> | 2026-06-23 11:37:23 +0800 |
|---|---|---|
| committer | Alex Deucher <alexander.deucher@amd.com> | 2026-07-01 11:28:03 -0400 |
| commit | 3a8d8e0b7f61cd759d5d4870b6220161f8a5b114 (patch) | |
| tree | c374d4f760adf1bd00938322d94e13de66e71381 | |
| parent | 1ac24df78c566d767a5ef05a1fe0ecc55bac248d (diff) | |
| download | linux-stable-3a8d8e0b7f61cd759d5d4870b6220161f8a5b114.tar.gz linux-stable-3a8d8e0b7f61cd759d5d4870b6220161f8a5b114.zip | |
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>
3 files changed, 52 insertions, 21 deletions
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c index d32c8166f703..f1fd6d4520c8 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_processpptables.c @@ -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; } - diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c index 55e13f376039..dcb9c749eba3 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega12_processpptables.c @@ -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); diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c index 36cb7aa80d07..a0c884c2341d 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c @@ -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); |
