]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
platform/wmi: Extend wmidev_invoke_method() to reject undersized data
authorArmin Wolf <W_Armin@gmx.de>
Mon, 6 Apr 2026 20:32:35 +0000 (22:32 +0200)
committerIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Mon, 13 Apr 2026 11:11:24 +0000 (14:11 +0300)
WMI drivers using the buffer-based WMI API are expected to reject
undersized method return values. Extend wmidev_invoke_method() to
enable the WMI driver core to perform this size check internally.

Signed-off-by: Armin Wolf <W_Armin@gmx.de>
Link: https://patch.msgid.link/20260406203237.2970-5-W_Armin@gmx.de
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
drivers/platform/wmi/core.c
drivers/platform/x86/bitland-mifs-wmi.c
include/linux/wmi.h

index 66ec885bffd7afa992ed821421098528a96875dd..a1a612f33233e9a0858e3a5e4545fd518f04147c 100644 (file)
@@ -364,20 +364,23 @@ acpi_status wmidev_evaluate_method(struct wmi_device *wdev, u8 instance, u32 met
 EXPORT_SYMBOL_GPL(wmidev_evaluate_method);
 
 /**
- * wmidev_invoke_method - Invoke a WMI method
+ * wmidev_invoke_method - Invoke a WMI method that returns values
  * @wdev: A wmi bus device from a driver
  * @instance: Instance index
  * @method_id: Method ID to call
  * @in: Mandatory WMI buffer containing input for the method call
- * @out: Optional WMI buffer to return the method results
+ * @out: Mandatory WMI buffer to return the method results
+ * @min_size: Minimum size of the method result data in bytes
  *
- * Invoke a WMI method, the caller must free the resulting data inside @out.
- * Said data is guaranteed to be aligned on a 8-byte boundary.
+ * Invoke a WMI method that returns values, the caller must free the resulting
+ * data inside @out using kfree(). Said data is guaranteed to be aligned on a
+ * 8-byte boundary. Use wmidev_invoke_procedure() for WMI methods that
+ * return no values.
  *
  * Return: 0 on success or negative error code on failure.
  */
 int wmidev_invoke_method(struct wmi_device *wdev, u8 instance, u32 method_id,
-                        const struct wmi_buffer *in, struct wmi_buffer *out)
+                        const struct wmi_buffer *in, struct wmi_buffer *out, size_t min_size)
 {
        struct wmi_block *wblock = container_of(wdev, struct wmi_block, dev);
        struct acpi_buffer aout = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -398,10 +401,7 @@ int wmidev_invoke_method(struct wmi_device *wdev, u8 instance, u32 method_id,
                ain.pointer = in->data;
        }
 
-       if (out)
-               status = wmidev_evaluate_method(wdev, instance, method_id, &ain, &aout);
-       else
-               status = wmidev_evaluate_method(wdev, instance, method_id, &ain, NULL);
+       status = wmidev_evaluate_method(wdev, instance, method_id, &ain, &aout);
 
        if (wblock->gblock.flags & ACPI_WMI_STRING)
                kfree(ain.pointer);
@@ -409,9 +409,6 @@ int wmidev_invoke_method(struct wmi_device *wdev, u8 instance, u32 method_id,
        if (ACPI_FAILURE(status))
                return -EIO;
 
-       if (!out)
-               return 0;
-
        obj = aout.pointer;
        if (!obj) {
                out->length = 0;
@@ -420,7 +417,7 @@ int wmidev_invoke_method(struct wmi_device *wdev, u8 instance, u32 method_id,
                return 0;
        }
 
-       ret = wmi_unmarshal_acpi_object(obj, out, 0);
+       ret = wmi_unmarshal_acpi_object(obj, out, min_size);
        kfree(obj);
 
        return ret;
index cd3cdd0875119007aa160b8dcaef0a2898405fd6..78639407d67eb842c00769719e10b5afaa856c58 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/acpi.h>
 #include <linux/array_size.h>
 #include <linux/bits.h>
-#include <linux/cleanup.h>
 #include <linux/container_of.h>
 #include <linux/dev_printk.h>
 #include <linux/device.h>
@@ -167,7 +166,6 @@ static int bitland_mifs_wmi_call(struct bitland_mifs_wmi_data *data,
                                 struct bitland_mifs_output *output)
 {
        struct wmi_buffer in_buf = { .length = sizeof(*input), .data = (void *)input };
-       void *out_data __free(kfree) = NULL;
        struct wmi_buffer out_buf = { 0 };
        int ret;
 
@@ -176,15 +174,12 @@ static int bitland_mifs_wmi_call(struct bitland_mifs_wmi_data *data,
        if (!output)
                return wmidev_invoke_procedure(data->wdev, 0, 1, &in_buf);
 
-       ret = wmidev_invoke_method(data->wdev, 0, 1, &in_buf, &out_buf);
+       ret = wmidev_invoke_method(data->wdev, 0, 1, &in_buf, &out_buf, sizeof(*output));
        if (ret)
                return ret;
 
-       out_data = out_buf.data;
-       if (out_buf.length < sizeof(*output))
-               return -EIO;
-
-       memcpy(output, out_data, sizeof(*output));
+       memcpy(output, out_buf.data, sizeof(*output));
+       kfree(out_buf.data);
 
        return 0;
 }
index b00950dc1231ac3c95126423698994b80e4cd4c4..858398beb01a6fb4bfcd92b3ac51420bf710b1c5 100644 (file)
@@ -68,7 +68,7 @@ ssize_t wmi_string_from_utf8s(struct wmi_string *str, size_t max_chars, const u8
                              size_t src_length);
 
 int wmidev_invoke_method(struct wmi_device *wdev, u8 instance, u32 method_id,
-                        const struct wmi_buffer *in, struct wmi_buffer *out);
+                        const struct wmi_buffer *in, struct wmi_buffer *out, size_t min_size);
 
 int wmidev_invoke_procedure(struct wmi_device *wdev, u8 instance, u32 method_id,
                            const struct wmi_buffer *in);