Add a min_size parameter to amdgpu_atif_call() to validate that the returned ACPI buffer is of type ACPI_TYPE_BUFFER, holds at least a u16 size field, does not claim more data than was actually returned, and meets the minimum size required by the calling function. Each caller passes its required minimum via sizeof() or offsetof() of the expected output struct and drops its own size check.
Signed-off-by: Lijo Lazar <[email protected]> Assisted-by: Claude Sonnet (Cursor AI) --- drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 68 ++++++++++++------------ 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index 02d5abf9df2b..b133f50d82ba 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -140,13 +140,15 @@ static struct amdgpu_acpi_priv { * @atif: atif structure * @function: the ATIF function to execute * @params: ATIF function params + * @min_size: minimum size of the expected output buffer in bytes * * Executes the requested ATIF function (all asics). * Returns a pointer to the acpi output buffer. */ static union acpi_object *amdgpu_atif_call(struct amdgpu_atif *atif, int function, - struct acpi_buffer *params) + struct acpi_buffer *params, + size_t min_size) { acpi_status status; union acpi_object *obj; @@ -189,6 +191,28 @@ static union acpi_object *amdgpu_atif_call(struct amdgpu_atif *atif, return NULL; } + if (obj->buffer.length < sizeof(u16)) { + DRM_DEBUG_DRIVER("ATIF buffer too small to hold size field: %u\n", + obj->buffer.length); + kfree(obj); + return NULL; + } + + if (obj->buffer.length < *(u16 *)obj->buffer.pointer) { + DRM_DEBUG_DRIVER("ATIF buffer length mismatch: reported %u, actual %u\n", + *(u16 *)obj->buffer.pointer, + obj->buffer.length); + kfree(obj); + return NULL; + } + + if (*(u16 *)obj->buffer.pointer < min_size) { + DRM_DEBUG_DRIVER("ATIF buffer too small: expected %zu, got %u\n", + min_size, *(u16 *)obj->buffer.pointer); + kfree(obj); + return NULL; + } + return obj; } @@ -251,19 +275,14 @@ int amdgpu_atif_verify_interface(struct amdgpu_atif *atif) size_t size; int err = 0; - info = amdgpu_atif_call(atif, ATIF_FUNCTION_VERIFY_INTERFACE, NULL); + info = amdgpu_atif_call(atif, ATIF_FUNCTION_VERIFY_INTERFACE, NULL, + sizeof(output)); if (!info) return -EIO; memset(&output, 0, sizeof(output)); - size = *(u16 *) info->buffer.pointer; - if (size < 12) { - DRM_INFO("ATIF buffer is too small: %zu\n", size); - err = -EINVAL; - goto out; - } - size = min(sizeof(output), size); + size = min(sizeof(output), (size_t)*(u16 *)info->buffer.pointer); memcpy(&output, info->buffer.pointer, size); @@ -273,7 +292,6 @@ int amdgpu_atif_verify_interface(struct amdgpu_atif *atif) amdgpu_atif_parse_notification(&atif->notifications, output.notification_mask); amdgpu_atif_parse_functions(&atif->functions, output.function_bits); -out: kfree(info); return err; } @@ -299,20 +317,14 @@ int amdgpu_atif_get_notification_params(struct amdgpu_atif *atif) int err = 0; info = amdgpu_atif_call(atif, ATIF_FUNCTION_GET_SYSTEM_PARAMETERS, - NULL); + NULL, offsetof(struct atif_system_params, command_code)); if (!info) { err = -EIO; goto out; } - size = *(u16 *) info->buffer.pointer; - if (size < 10) { - err = -EINVAL; - goto out; - } - memset(¶ms, 0, sizeof(params)); - size = min(sizeof(params), size); + size = min(sizeof(params), (size_t)*(u16 *)info->buffer.pointer); memcpy(¶ms, info->buffer.pointer, size); DRM_DEBUG_DRIVER("SYSTEM_PARAMS: mask = %#x, flags = %#x\n", @@ -376,20 +388,14 @@ int amdgpu_atif_query_backlight_caps(struct amdgpu_atif *atif) info = amdgpu_atif_call(atif, ATIF_FUNCTION_QUERY_BRIGHTNESS_TRANSFER_CHARACTERISTICS, - ¶ms); + ¶ms, offsetof(struct atif_qbtc_output, data_points)); if (!info) { err = -EIO; goto out; } - size = *(u16 *) info->buffer.pointer; - if (size < 10) { - err = -EINVAL; - goto out; - } - memset(&characteristics, 0, sizeof(characteristics)); - size = min(sizeof(characteristics), size); + size = min(sizeof(characteristics), (size_t)*(u16 *)info->buffer.pointer); memcpy(&characteristics, info->buffer.pointer, size); atif->backlight_caps.caps_valid = true; @@ -427,24 +433,18 @@ static int amdgpu_atif_get_sbios_requests(struct amdgpu_atif *atif, int count = 0; info = amdgpu_atif_call(atif, ATIF_FUNCTION_GET_SYSTEM_BIOS_REQUESTS, - NULL); + NULL, sizeof(*req)); if (!info) return -EIO; - size = *(u16 *)info->buffer.pointer; - if (size < 0xd) { - count = -EINVAL; - goto out; - } memset(req, 0, sizeof(*req)); - size = min(sizeof(*req), size); + size = min(sizeof(*req), (size_t)*(u16 *)info->buffer.pointer); memcpy(req, info->buffer.pointer, size); DRM_DEBUG_DRIVER("SBIOS pending requests: %#x\n", req->pending); count = hweight32(req->pending); -out: kfree(info); return count; } -- 2.49.0
