From 20594cd104abaaabb676c7a2915b150ae5ff093d Mon Sep 17 00:00:00 2001 From: Kaushlendra Kumar Date: Mon, 6 Oct 2025 14:17:06 +0530 Subject: ACPI: button: Call input_free_device() on failing input device registration Make acpi_button_add() call input_free_device() when input_register_device() fails as required according to the documentation of the latter. Fixes: 0d51157dfaac ("ACPI: button: Eliminate the driver notify callback") Signed-off-by: Kaushlendra Kumar Cc: 6.5+ # 6.5+ [ rjw: Subject and changelog rewrite, Fixes: tag ] Link: https://patch.msgid.link/20251006084706.971855-1-kaushlendra.kumar@intel.com Signed-off-by: Rafael J. Wysocki --- drivers/acpi/button.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 0a7026040188..3c6dd9b4ba0a 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -619,8 +619,10 @@ static int acpi_button_add(struct acpi_device *device) input_set_drvdata(input, device); error = input_register_device(input); - if (error) + if (error) { + input_free_device(input); goto err_remove_fs; + } switch (device->device_type) { case ACPI_BUS_TYPE_POWER_BUTTON: -- cgit From 8f067aa59430266386b83c18b983ca583faa6a11 Mon Sep 17 00:00:00 2001 From: Yuhao Jiang Date: Wed, 22 Oct 2025 15:07:04 -0500 Subject: ACPI: video: Fix use-after-free in acpi_video_switch_brightness() The switch_brightness_work delayed work accesses device->brightness and device->backlight, freed by acpi_video_dev_unregister_backlight() during device removal. If the work executes after acpi_video_bus_unregister_backlight() frees these resources, it causes a use-after-free when acpi_video_switch_brightness() dereferences device->brightness or device->backlight. Fix this by calling cancel_delayed_work_sync() for each device's switch_brightness_work in acpi_video_bus_remove_notify_handler() after removing the notify handler that queues the work. This ensures the work completes before the memory is freed. Fixes: 8ab58e8e7e097 ("ACPI / video: Fix backlight taking 2 steps on a brightness up/down keypress") Cc: All applicable Signed-off-by: Yuhao Jiang Reviewed-by: Hans de Goede [ rjw: Changelog edit ] Link: https://patch.msgid.link/20251022200704.2655507-1-danisjiang@gmail.com Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_video.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 103f29661576..be8e7e18abca 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -1959,8 +1959,10 @@ static void acpi_video_bus_remove_notify_handler(struct acpi_video_bus *video) struct acpi_video_device *dev; mutex_lock(&video->device_list_lock); - list_for_each_entry(dev, &video->video_device_list, entry) + list_for_each_entry(dev, &video->video_device_list, entry) { acpi_video_dev_remove_notify_handler(dev); + cancel_delayed_work_sync(&dev->switch_brightness_work); + } mutex_unlock(&video->device_list_lock); acpi_video_bus_stop_devices(video); -- cgit From 58764259ebe0c9efd569194444629f6b26f86583 Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Wed, 8 Oct 2025 01:41:44 +0200 Subject: ACPI: fan: Use ACPI handle when retrieving _FST Usage of the ACPI device should be phased out in the future, as the driver itself is now using the platform bus. Replace any usage of struct acpi_device in acpi_fan_get_fst() to allow users to drop usage of struct acpi_device. Also extend the integer check to all three package elements. Signed-off-by: Armin Wolf Link: https://patch.msgid.link/20251007234149.2769-2-W_Armin@gmx.de Signed-off-by: Rafael J. Wysocki --- drivers/acpi/fan.h | 3 ++- drivers/acpi/fan_attr.c | 2 +- drivers/acpi/fan_core.c | 34 ++++++++++++++++++++++------------ drivers/acpi/fan_hwmon.c | 3 +-- 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/drivers/acpi/fan.h b/drivers/acpi/fan.h index 8a28a72a7c6a..d39bb6fd1326 100644 --- a/drivers/acpi/fan.h +++ b/drivers/acpi/fan.h @@ -49,6 +49,7 @@ struct acpi_fan_fst { }; struct acpi_fan { + acpi_handle handle; bool acpi4; bool has_fst; struct acpi_fan_fif fif; @@ -59,7 +60,7 @@ struct acpi_fan { struct device_attribute fine_grain_control; }; -int acpi_fan_get_fst(struct acpi_device *device, struct acpi_fan_fst *fst); +int acpi_fan_get_fst(acpi_handle handle, struct acpi_fan_fst *fst); int acpi_fan_create_attributes(struct acpi_device *device); void acpi_fan_delete_attributes(struct acpi_device *device); diff --git a/drivers/acpi/fan_attr.c b/drivers/acpi/fan_attr.c index c1afb7b5ed3d..9b7fa52f3c2a 100644 --- a/drivers/acpi/fan_attr.c +++ b/drivers/acpi/fan_attr.c @@ -55,7 +55,7 @@ static ssize_t show_fan_speed(struct device *dev, struct device_attribute *attr, struct acpi_fan_fst fst; int status; - status = acpi_fan_get_fst(acpi_dev, &fst); + status = acpi_fan_get_fst(acpi_dev->handle, &fst); if (status) return status; diff --git a/drivers/acpi/fan_core.c b/drivers/acpi/fan_core.c index 04ff608f2ff0..ea2c646c470c 100644 --- a/drivers/acpi/fan_core.c +++ b/drivers/acpi/fan_core.c @@ -44,25 +44,30 @@ static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long return 0; } -int acpi_fan_get_fst(struct acpi_device *device, struct acpi_fan_fst *fst) +int acpi_fan_get_fst(acpi_handle handle, struct acpi_fan_fst *fst) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *obj; acpi_status status; int ret = 0; - status = acpi_evaluate_object(device->handle, "_FST", NULL, &buffer); - if (ACPI_FAILURE(status)) { - dev_err(&device->dev, "Get fan state failed\n"); - return -ENODEV; - } + status = acpi_evaluate_object(handle, "_FST", NULL, &buffer); + if (ACPI_FAILURE(status)) + return -EIO; obj = buffer.pointer; - if (!obj || obj->type != ACPI_TYPE_PACKAGE || - obj->package.count != 3 || - obj->package.elements[1].type != ACPI_TYPE_INTEGER) { - dev_err(&device->dev, "Invalid _FST data\n"); - ret = -EINVAL; + if (!obj) + return -ENODATA; + + if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3) { + ret = -EPROTO; + goto err; + } + + if (obj->package.elements[0].type != ACPI_TYPE_INTEGER || + obj->package.elements[1].type != ACPI_TYPE_INTEGER || + obj->package.elements[2].type != ACPI_TYPE_INTEGER) { + ret = -EPROTO; goto err; } @@ -81,7 +86,7 @@ static int fan_get_state_acpi4(struct acpi_device *device, unsigned long *state) struct acpi_fan_fst fst; int status, i; - status = acpi_fan_get_fst(device, &fst); + status = acpi_fan_get_fst(device->handle, &fst); if (status) return status; @@ -311,11 +316,16 @@ static int acpi_fan_probe(struct platform_device *pdev) struct acpi_device *device = ACPI_COMPANION(&pdev->dev); char *name; + if (!device) + return -ENODEV; + fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL); if (!fan) { dev_err(&device->dev, "No memory for fan\n"); return -ENOMEM; } + + fan->handle = device->handle; device->driver_data = fan; platform_set_drvdata(pdev, fan); diff --git a/drivers/acpi/fan_hwmon.c b/drivers/acpi/fan_hwmon.c index e8d90605106e..4209a9923efc 100644 --- a/drivers/acpi/fan_hwmon.c +++ b/drivers/acpi/fan_hwmon.c @@ -93,13 +93,12 @@ static umode_t acpi_fan_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_ static int acpi_fan_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { - struct acpi_device *adev = to_acpi_device(dev->parent); struct acpi_fan *fan = dev_get_drvdata(dev); struct acpi_fan_fps *fps; struct acpi_fan_fst fst; int ret; - ret = acpi_fan_get_fst(adev, &fst); + ret = acpi_fan_get_fst(fan->handle, &fst); if (ret < 0) return ret; -- cgit From d91a1d129b63614fa4c2e45e60918409ce36db7e Mon Sep 17 00:00:00 2001 From: Armin Wolf Date: Wed, 8 Oct 2025 01:41:46 +0200 Subject: ACPI: fan: Use platform device for devres-related actions Device-managed resources are cleaned up when the driver unbinds from the underlying device. In our case this is the platform device as this driver is a platform driver. Registering device-managed resources on the associated ACPI device will thus result in a resource leak when this driver unbinds. Ensure that any device-managed resources are only registered on the platform device to ensure that they are cleaned up during removal. Fixes: 35c50d853adc ("ACPI: fan: Add hwmon support") Signed-off-by: Armin Wolf Cc: 6.11+ # 6.11+ Link: https://patch.msgid.link/20251007234149.2769-4-W_Armin@gmx.de Signed-off-by: Rafael J. Wysocki --- drivers/acpi/fan.h | 4 ++-- drivers/acpi/fan_core.c | 2 +- drivers/acpi/fan_hwmon.c | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/fan.h b/drivers/acpi/fan.h index d39bb6fd1326..bedbab0e8e4e 100644 --- a/drivers/acpi/fan.h +++ b/drivers/acpi/fan.h @@ -65,9 +65,9 @@ int acpi_fan_create_attributes(struct acpi_device *device); void acpi_fan_delete_attributes(struct acpi_device *device); #if IS_REACHABLE(CONFIG_HWMON) -int devm_acpi_fan_create_hwmon(struct acpi_device *device); +int devm_acpi_fan_create_hwmon(struct device *dev); #else -static inline int devm_acpi_fan_create_hwmon(struct acpi_device *device) { return 0; }; +static inline int devm_acpi_fan_create_hwmon(struct device *dev) { return 0; }; #endif #endif diff --git a/drivers/acpi/fan_core.c b/drivers/acpi/fan_core.c index ea2c646c470c..46e7fe7a506d 100644 --- a/drivers/acpi/fan_core.c +++ b/drivers/acpi/fan_core.c @@ -347,7 +347,7 @@ static int acpi_fan_probe(struct platform_device *pdev) } if (fan->has_fst) { - result = devm_acpi_fan_create_hwmon(device); + result = devm_acpi_fan_create_hwmon(&pdev->dev); if (result) return result; diff --git a/drivers/acpi/fan_hwmon.c b/drivers/acpi/fan_hwmon.c index 4209a9923efc..4b2c2007f2d7 100644 --- a/drivers/acpi/fan_hwmon.c +++ b/drivers/acpi/fan_hwmon.c @@ -166,12 +166,12 @@ static const struct hwmon_chip_info acpi_fan_hwmon_chip_info = { .info = acpi_fan_hwmon_info, }; -int devm_acpi_fan_create_hwmon(struct acpi_device *device) +int devm_acpi_fan_create_hwmon(struct device *dev) { - struct acpi_fan *fan = acpi_driver_data(device); + struct acpi_fan *fan = dev_get_drvdata(dev); struct device *hdev; - hdev = devm_hwmon_device_register_with_info(&device->dev, "acpi_fan", fan, - &acpi_fan_hwmon_chip_info, NULL); + hdev = devm_hwmon_device_register_with_info(dev, "acpi_fan", fan, &acpi_fan_hwmon_chip_info, + NULL); return PTR_ERR_OR_ZERO(hdev); } -- cgit