gpiod_line_state_notify() races with a concurrent gpiochip_remove() which unconditionally destroys the line state workqueue causing a use-after-free situation where queue_work() can schedule a work on a freed workqueue. Keep the line state workqueue alive until GPIO device release. Cc: stable@vger.kernel.org Fixes: 07c61d4da43f ("gpiolib: notify user-space about in-kernel line state changes") Closes: https://sashiko.dev/#/bug/linux-d0e9e518-2348-4fe3-857d-f3d61a42f159 Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib-cdev.c | 1 - drivers/gpio/gpiolib.c | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib-cdev.c b/drivers/gpio/gpiolib-cdev.c index f68e33cbd7d4cd5153e82ad77768cf52a90601d6..1dc170364c46a51092d21391c5a602bf9dee820c 100644 --- a/drivers/gpio/gpiolib-cdev.c +++ b/drivers/gpio/gpiolib-cdev.c @@ -2768,7 +2768,6 @@ int gpiolib_cdev_register(struct gpio_chip *gc, dev_t devt) void gpiolib_cdev_unregister(struct gpio_device *gdev) { - destroy_workqueue(gdev->line_state_wq); cdev_device_del(&gdev->chrdev, &gdev->dev); blocking_notifier_call_chain(&gdev->device_notifier, 0, NULL); } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index fbdeda2f278713a47c2e3d2a6640f387f6d92227..c954c7eec2bee3a8dd55b949ec9b92f31461b25d 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -898,6 +899,9 @@ static void gpiodev_release(struct device *dev) synchronize_srcu(&gdev->desc_srcu); cleanup_srcu_struct(&gdev->desc_srcu); + if (gdev->line_state_wq) + destroy_workqueue(gdev->line_state_wq); + ida_free(&gpio_ida, gdev->id); kfree_const(gdev->label); kfree(gdev->descs); --- base-commit: ddfe51b0a0f5dc9e415cc2c8ad8db17532dd426b change-id: 20261109-gpio-line-state-wq-uaf-e7343655998a Best regards, -- Bartosz Golaszewski