diff --git a/drivers/platform/wmi/core.c b/drivers/platform/wmi/core.c index 7cc5ca11a60d..66ec885bffd7 100644 --- a/drivers/platform/wmi/core.c +++ b/drivers/platform/wmi/core.c @@ -420,7 +420,7 @@ int wmidev_invoke_method(struct wmi_device *wdev, u8 instance, u32 method_id, return 0; } - ret = wmi_unmarshal_acpi_object(obj, out); + ret = wmi_unmarshal_acpi_object(obj, out, 0); kfree(obj); return ret; @@ -583,7 +583,7 @@ int wmidev_query_block(struct wmi_device *wdev, u8 instance, struct wmi_buffer * if (!obj) return -EIO; - ret = wmi_unmarshal_acpi_object(obj, out); + ret = wmi_unmarshal_acpi_object(obj, out, 0); kfree(obj); return ret; @@ -1416,7 +1416,7 @@ static void wmi_notify_driver(struct wmi_block *wblock, union acpi_object *obj) return; } - ret = wmi_unmarshal_acpi_object(obj, &buffer); + ret = wmi_unmarshal_acpi_object(obj, &buffer, 0); if (ret < 0) { dev_warn(&wblock->dev.dev, "Failed to unmarshal event data: %d\n", ret); return; diff --git a/drivers/platform/wmi/internal.h b/drivers/platform/wmi/internal.h index 9a39ffa31ad1..c02908694563 100644 --- a/drivers/platform/wmi/internal.h +++ b/drivers/platform/wmi/internal.h @@ -11,7 +11,8 @@ union acpi_object; struct wmi_buffer; -int wmi_unmarshal_acpi_object(const union acpi_object *obj, struct wmi_buffer *buffer); +int wmi_unmarshal_acpi_object(const union acpi_object *obj, struct wmi_buffer *buffer, + size_t min_size); int wmi_marshal_string(const struct wmi_buffer *buffer, struct acpi_buffer *out); #endif /* _WMI_INTERNAL_H_ */ diff --git a/drivers/platform/wmi/marshalling.c b/drivers/platform/wmi/marshalling.c index 63a92c4ebab5..87091832568e 100644 --- a/drivers/platform/wmi/marshalling.c +++ b/drivers/platform/wmi/marshalling.c @@ -151,7 +151,8 @@ static int wmi_obj_transform(const union acpi_object *obj, u8 *buffer) return 0; } -int wmi_unmarshal_acpi_object(const union acpi_object *obj, struct wmi_buffer *buffer) +int wmi_unmarshal_acpi_object(const union acpi_object *obj, struct wmi_buffer *buffer, + size_t min_size) { size_t length, alloc_length; u8 *data; @@ -161,6 +162,9 @@ int wmi_unmarshal_acpi_object(const union acpi_object *obj, struct wmi_buffer *b if (ret < 0) return ret; + if (length < min_size) + return -ENODATA; + if (ARCH_KMALLOC_MINALIGN < 8) { /* * kmalloc() guarantees that the alignment of the resulting memory allocation is at diff --git a/drivers/platform/wmi/tests/marshalling_kunit.c b/drivers/platform/wmi/tests/marshalling_kunit.c index 0c7cd8774aa3..471963076d58 100644 --- a/drivers/platform/wmi/tests/marshalling_kunit.c +++ b/drivers/platform/wmi/tests/marshalling_kunit.c @@ -372,7 +372,7 @@ static void wmi_unmarshal_acpi_object_test(struct kunit *test) struct wmi_buffer result; int ret; - ret = wmi_unmarshal_acpi_object(¶m->obj, &result); + ret = wmi_unmarshal_acpi_object(¶m->obj, &result, param->buffer.length); if (ret < 0) KUNIT_FAIL_AND_ABORT(test, "Unmarshalling of ACPI object failed\n"); @@ -389,7 +389,7 @@ static void wmi_unmarshal_acpi_object_failure_test(struct kunit *test) struct wmi_buffer result; int ret; - ret = wmi_unmarshal_acpi_object(¶m->obj, &result); + ret = wmi_unmarshal_acpi_object(¶m->obj, &result, 0); if (ret < 0) return; @@ -427,6 +427,25 @@ static void wmi_marshal_string_failure_test(struct kunit *test) KUNIT_FAIL(test, "Invalid string was not rejected\n"); } +static void wmi_unmarshal_acpi_object_undersized_test(struct kunit *test) +{ + const union acpi_object obj = { + .integer = { + .type = ACPI_TYPE_INTEGER, + .value = 0xdeadbeef, + }, + }; + struct wmi_buffer result; + int ret; + + ret = wmi_unmarshal_acpi_object(&obj, &result, sizeof(expected_single_integer) + 1); + if (ret < 0) + return; + + kfree(result.data); + KUNIT_FAIL(test, "Undersized unmarshalling result was not rejected\n"); +} + static struct kunit_case wmi_marshalling_test_cases[] = { KUNIT_CASE_PARAM(wmi_unmarshal_acpi_object_test, wmi_unmarshal_acpi_object_gen_params), @@ -436,6 +455,7 @@ static struct kunit_case wmi_marshalling_test_cases[] = { wmi_unmarshal_acpi_object_failure_gen_params), KUNIT_CASE_PARAM(wmi_marshal_string_failure_test, wmi_marshal_string_failure_gen_params), + KUNIT_CASE(wmi_unmarshal_acpi_object_undersized_test), {} };