Reject voltage objects whose usSize is smaller than the header or would
advance the cursor past the table end, preventing an infinite loop or
heap OOB read when the VBIOS supplies a malformed VoltageObjectInfo table.

Fixes: c82baa281843 ("drm/amd/powerplay: add Tonga dpm support (v3)")
Fixes: 0d2c7569e196 ("drm/amdgpu: add new atomfirmware based helpers for 
powerplay")

Signed-off-by: Asad Kamal <[email protected]>
Reviewed-by: Lijo Lazar <[email protected]>
---
 drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c   | 10 ++++++++--
 drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c | 11 ++++++++---
 2 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c 
b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c
index ce166a7f8e42..1fff7567bca2 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomctrl.c
@@ -268,15 +268,21 @@ static const ATOM_VOLTAGE_OBJECT_V3 
*atomctrl_lookup_voltage_type_v3(
        unsigned int offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, 
asVoltageObj[0]);
        uint8_t *start = (uint8_t *)voltage_object_info_table;
 
-       while (offset < size) {
+       while (offset + sizeof(ATOM_VOLTAGE_OBJECT_HEADER_V3) <= size) {
                const ATOM_VOLTAGE_OBJECT_V3 *voltage_object =
                        (const ATOM_VOLTAGE_OBJECT_V3 *)(start + offset);
+               u16 obj_size;
+
+               obj_size = 
le16_to_cpu(voltage_object->asGpioVoltageObj.sHeader.usSize);
+               if (obj_size < sizeof(voltage_object->asGpioVoltageObj.sHeader) 
||
+                   offset + obj_size > size)
+                       break;
 
                if (voltage_type == 
voltage_object->asGpioVoltageObj.sHeader.ucVoltageType &&
                        voltage_mode == 
voltage_object->asGpioVoltageObj.sHeader.ucVoltageMode)
                        return voltage_object;
 
-               offset += 
le16_to_cpu(voltage_object->asGpioVoltageObj.sHeader.usSize);
+               offset += obj_size;
        }
 
        return NULL;
diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c 
b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c
index 6120f14caab0..69aee8661d1e 100644
--- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c
+++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/ppatomfwctrl.c
@@ -36,16 +36,21 @@ static const union atom_voltage_object_v4 
*pp_atomfwctrl_lookup_voltage_type_v4(
                        offsetof(struct atom_voltage_objects_info_v4_1, 
voltage_object[0]);
        unsigned long start = (unsigned long)voltage_object_info_table;
 
-       while (offset < size) {
+       while (offset + sizeof(struct atom_voltage_object_header_v4) <= size) {
                const union atom_voltage_object_v4 *voltage_object =
                        (const union atom_voltage_object_v4 *)(start + offset);
+               u16 obj_size;
+
+               obj_size = 
le16_to_cpu(voltage_object->gpio_voltage_obj.header.object_size);
+               if (obj_size < sizeof(voltage_object->gpio_voltage_obj.header) 
||
+                   offset + obj_size > size)
+                       break;
 
                if (voltage_type == 
voltage_object->gpio_voltage_obj.header.voltage_type &&
                    voltage_mode == 
voltage_object->gpio_voltage_obj.header.voltage_mode)
                        return voltage_object;
 
-               offset += 
le16_to_cpu(voltage_object->gpio_voltage_obj.header.object_size);
-
+               offset += obj_size;
        }
 
        return NULL;
-- 
2.46.0

Reply via email to