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

Reply via email to