From: Armin Wolf Date: Mon, 6 Apr 2026 20:32:35 +0000 (+0200) Subject: platform/wmi: Extend wmidev_invoke_method() to reject undersized data X-Git-Url: http://git.ipfire.org/index.cgi?a=commitdiff_plain;h=96b1b053e10d89f666a37b52be25ed4294e342be;p=thirdparty%2Flinux.git platform/wmi: Extend wmidev_invoke_method() to reject undersized data 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 Link: https://patch.msgid.link/20260406203237.2970-5-W_Armin@gmx.de Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- diff --git a/drivers/platform/wmi/core.c b/drivers/platform/wmi/core.c index 66ec885bffd7..a1a612f33233 100644 --- a/drivers/platform/wmi/core.c +++ b/drivers/platform/wmi/core.c @@ -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; diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c index cd3cdd087511..78639407d67e 100644 --- a/drivers/platform/x86/bitland-mifs-wmi.c +++ b/drivers/platform/x86/bitland-mifs-wmi.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -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; } diff --git a/include/linux/wmi.h b/include/linux/wmi.h index b00950dc1231..858398beb01a 100644 --- a/include/linux/wmi.h +++ b/include/linux/wmi.h @@ -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);