summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c68
1 files 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 516ab9cf88fc..7f5abb03be1b 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(&params, 0, sizeof(params));
- size = min(sizeof(params), size);
+ size = min(sizeof(params), (size_t)*(u16 *)info->buffer.pointer);
memcpy(&params, 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,
- &params);
+ &params, 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;
}