drm/amd/powerplay: fix VoltageObjectInfo zero-stride loop and OOB read

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: c82baa2818 ("drm/amd/powerplay: add Tonga dpm support (v3)")
Fixes: 0d2c7569e1 ("drm/amdgpu: add new atomfirmware based helpers for powerplay")
Signed-off-by: Asad Kamal <asad.kamal@amd.com>
Reviewed-by: Lijo Lazar <lijo.lazar@amd.com>
Reviewed-by: Yang Wang <kevinyang.wang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Asad Kamal 2026-06-23 00:25:04 +08:00 committed by Alex Deucher
parent 6c2abd0ec0
commit 5d3cc8e388
2 changed files with 16 additions and 5 deletions

View File

@ -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;

View File

@ -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;