[PATCH 3/6] platform/wmi: Prepare to reject undersized unmarshalling results

From: Armin Wolf

Date: Mon Apr 06 2026 - 17:20:33 EST


Driver using the buffer-based WMI API usually reject buffers resulting
from WMI method calls or block queries if they contain not enough data.
Prepare the WMI core for assisting in this by automatically rejecting
undersized unmarshalling results.

Signed-off-by: Armin Wolf <W_Armin@xxxxxx>
---
drivers/platform/wmi/core.c | 6 ++---
drivers/platform/wmi/internal.h | 3 ++-
drivers/platform/wmi/marshalling.c | 6 ++++-
.../platform/wmi/tests/marshalling_kunit.c | 24 +++++++++++++++++--
4 files changed, 32 insertions(+), 7 deletions(-)

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(&param->obj, &result);
+ ret = wmi_unmarshal_acpi_object(&param->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(&param->obj, &result);
+ ret = wmi_unmarshal_acpi_object(&param->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),
{}
};

--
2.39.5