ucNumEntries in the Tonga/Polaris PowerPlay sub-tables is used as both the
kzalloc count and loop bound without validation, allowing a crafted VBIOS
to overflow the destination heap object and read past the VBIOS image.
Clamp via pp_entries_max() in get_vddc_lookup_table(),
get_mclk_voltage_dependency_table(), get_sclk_voltage_dependency_table()
and get_mm_clock_voltage_table().
Fixes: c82baa281843 ("drm/amd/powerplay: add Tonga dpm support (v3)")
Signed-off-by: Asad Kamal <[email protected]>
Reviewed-by: Lijo Lazar <[email protected]>
---
.../powerplay/hwmgr/process_pptables_v1_0.c | 76 +++++++++++++++----
1 file changed, 61 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c
b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c
index 6cfef1b295ab..aff30f609414 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/process_pptables_v1_0.c
@@ -158,6 +158,7 @@ static int get_vddc_lookup_table(
)
{
uint32_t i;
+ uint32_t num_entries;
phm_ppt_v1_voltage_lookup_table *table;
phm_ppt_v1_voltage_lookup_record *record;
ATOM_Tonga_Voltage_Lookup_Record *atom_record;
@@ -165,13 +166,22 @@ static int get_vddc_lookup_table(
PP_ASSERT_WITH_CODE((0 != vddc_lookup_pp_tables->ucNumEntries),
"Invalid CAC Leakage PowerPlay Table!", return 1);
- table = kzalloc(struct_size(table, entries, max_levels), GFP_KERNEL);
+ num_entries = min_t(uint32_t, vddc_lookup_pp_tables->ucNumEntries,
+ min_t(uint32_t, max_levels,
+ pp_entries_max(hwmgr, vddc_lookup_pp_tables,
+ sizeof(*vddc_lookup_pp_tables),
+
sizeof(ATOM_Tonga_Voltage_Lookup_Record))));
+ if (num_entries < vddc_lookup_pp_tables->ucNumEntries)
+ pr_warn("amdgpu: VddcLookup table: clamping ucNumEntries %u ->
%u\n",
+ vddc_lookup_pp_tables->ucNumEntries, num_entries);
+
+ table = kzalloc(struct_size(table, entries, num_entries), GFP_KERNEL);
if (!table)
return -ENOMEM;
- table->count = vddc_lookup_pp_tables->ucNumEntries;
+ table->count = num_entries;
- for (i = 0; i < vddc_lookup_pp_tables->ucNumEntries; i++) {
+ for (i = 0; i < num_entries; i++) {
record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
phm_ppt_v1_voltage_lookup_record,
entries, table, i);
@@ -364,6 +374,7 @@ static int get_mclk_voltage_dependency_table(
)
{
uint32_t i;
+ uint32_t num_entries;
phm_ppt_v1_clock_voltage_dependency_table *mclk_table;
phm_ppt_v1_clock_voltage_dependency_record *mclk_table_record;
ATOM_Tonga_MCLK_Dependency_Record *mclk_dep_record;
@@ -371,14 +382,22 @@ static int get_mclk_voltage_dependency_table(
PP_ASSERT_WITH_CODE((0 != mclk_dep_table->ucNumEntries),
"Invalid PowerPlay Table!", return -1);
- mclk_table = kzalloc(struct_size(mclk_table, entries,
mclk_dep_table->ucNumEntries),
+ num_entries = min_t(uint32_t, mclk_dep_table->ucNumEntries,
+ pp_entries_max(hwmgr, mclk_dep_table,
+ sizeof(*mclk_dep_table),
+
sizeof(ATOM_Tonga_MCLK_Dependency_Record)));
+ if (num_entries < mclk_dep_table->ucNumEntries)
+ pr_warn("amdgpu: MCLK dependency table: clamping ucNumEntries
%u -> %u\n",
+ mclk_dep_table->ucNumEntries, num_entries);
+
+ mclk_table = kzalloc(struct_size(mclk_table, entries, num_entries),
GFP_KERNEL);
if (!mclk_table)
return -ENOMEM;
- mclk_table->count = (uint32_t)mclk_dep_table->ucNumEntries;
+ mclk_table->count = num_entries;
- for (i = 0; i < mclk_dep_table->ucNumEntries; i++) {
+ for (i = 0; i < num_entries; i++) {
mclk_table_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
phm_ppt_v1_clock_voltage_dependency_record,
entries, mclk_table, i);
@@ -404,6 +423,7 @@ static int get_sclk_voltage_dependency_table(
)
{
uint32_t i;
+ uint32_t num_entries;
phm_ppt_v1_clock_voltage_dependency_table *sclk_table;
phm_ppt_v1_clock_voltage_dependency_record *sclk_table_record;
@@ -415,14 +435,22 @@ static int get_sclk_voltage_dependency_table(
PP_ASSERT_WITH_CODE((0 != tonga_table->ucNumEntries),
"Invalid PowerPlay Table!", return -1);
- sclk_table = kzalloc(struct_size(sclk_table, entries,
tonga_table->ucNumEntries),
+ num_entries = min_t(uint32_t, tonga_table->ucNumEntries,
+ pp_entries_max(hwmgr, tonga_table,
+ sizeof(*tonga_table),
+
sizeof(ATOM_Tonga_SCLK_Dependency_Record)));
+ if (num_entries < tonga_table->ucNumEntries)
+ pr_warn("amdgpu: Tonga SCLK dependency table: clamping
ucNumEntries %u -> %u\n",
+ tonga_table->ucNumEntries, num_entries);
+
+ sclk_table = kzalloc(struct_size(sclk_table, entries,
num_entries),
GFP_KERNEL);
if (!sclk_table)
return -ENOMEM;
- sclk_table->count = (uint32_t)tonga_table->ucNumEntries;
+ sclk_table->count = num_entries;
- for (i = 0; i < tonga_table->ucNumEntries; i++) {
+ for (i = 0; i < num_entries; i++) {
sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
ATOM_Tonga_SCLK_Dependency_Record,
entries, tonga_table, i);
@@ -444,14 +472,22 @@ static int get_sclk_voltage_dependency_table(
PP_ASSERT_WITH_CODE((0 != polaris_table->ucNumEntries),
"Invalid PowerPlay Table!", return -1);
- sclk_table = kzalloc(struct_size(sclk_table, entries,
polaris_table->ucNumEntries),
+ num_entries = min_t(uint32_t, polaris_table->ucNumEntries,
+ pp_entries_max(hwmgr, polaris_table,
+ sizeof(*polaris_table),
+
sizeof(ATOM_Polaris_SCLK_Dependency_Record)));
+ if (num_entries < polaris_table->ucNumEntries)
+ pr_warn("amdgpu: Polaris SCLK dependency table:
clamping ucNumEntries %u -> %u\n",
+ polaris_table->ucNumEntries, num_entries);
+
+ sclk_table = kzalloc(struct_size(sclk_table, entries,
num_entries),
GFP_KERNEL);
if (!sclk_table)
return -ENOMEM;
- sclk_table->count = (uint32_t)polaris_table->ucNumEntries;
+ sclk_table->count = num_entries;
- for (i = 0; i < polaris_table->ucNumEntries; i++) {
+ for (i = 0; i < num_entries; i++) {
sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
ATOM_Polaris_SCLK_Dependency_Record,
entries, polaris_table, i);
@@ -718,20 +754,30 @@ static int get_mm_clock_voltage_table(
)
{
uint32_t i;
+ uint32_t num_entries;
const ATOM_Tonga_MM_Dependency_Record *mm_dependency_record;
phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table;
phm_ppt_v1_mm_clock_voltage_dependency_record *mm_table_record;
PP_ASSERT_WITH_CODE((0 != mm_dependency_table->ucNumEntries),
"Invalid PowerPlay Table!", return -1);
- mm_table = kzalloc(struct_size(mm_table, entries,
mm_dependency_table->ucNumEntries),
+
+ num_entries = min_t(uint32_t, mm_dependency_table->ucNumEntries,
+ pp_entries_max(hwmgr, mm_dependency_table,
+ sizeof(*mm_dependency_table),
+
sizeof(ATOM_Tonga_MM_Dependency_Record)));
+ if (num_entries < mm_dependency_table->ucNumEntries)
+ pr_warn("amdgpu: MM dependency table: clamping ucNumEntries %u
-> %u\n",
+ mm_dependency_table->ucNumEntries, num_entries);
+
+ mm_table = kzalloc(struct_size(mm_table, entries, num_entries),
GFP_KERNEL);
if (!mm_table)
return -ENOMEM;
- mm_table->count = mm_dependency_table->ucNumEntries;
+ mm_table->count = num_entries;
- for (i = 0; i < mm_dependency_table->ucNumEntries; i++) {
+ for (i = 0; i < num_entries; i++) {
mm_dependency_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
ATOM_Tonga_MM_Dependency_Record,
entries, mm_dependency_table,
i);
--
2.46.0