Re: [PATCH] HID: winwing: fix use-after-free in force feedback teardown

[email protected] Wed, 12 Aug 2026 17:26:52 +0000
Newsgroups org.kernel.vger.linux-input
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:

Pre-existing issues:
- [High] Incorrect teardown ordering in `winwing_remove()` causes `rumble_work` to be re-queued after cancellation, leading to a Use-After-Free.
- [High] The `lights_lock` mutex in `struct winwing_drv_data` is used without ever being initialized.
- [High] LED class devices remain registered after the hardware is stopped, leading to potential Use-After-Free or crashes in the low-level transport driver.
--

--- Patch [1]: [PATCH] HID: winwing: fix use-after-free in force feedback teardown ---
commit 7ead0cac4461910c7f089ed4dac8be573080aceb
Author: René Onier <[email protected]>

HID: winwing: fix use-after-free in force feedback teardown

winwing_init_ff() passes the driver's private data, allocated with
devm_kzalloc() in winwing_probe(), as the effect context to
input_ff_create_memless(). The memoryless force-feedback core takes
ownership of that pointer and frees it with kfree() from
input_ff_destroy() (ml_ff_destroy()) when the input device is
destroyed.

Fixes: 42d020b54edc ("HID: winwing: Enable rumble effects")

> diff --git a/drivers/hid/hid-winwing.c b/drivers/hid/hid-winwing.c
> index 9cd25a77999e6..19b92c2c6579a 100644
> --- a/drivers/hid/hid-winwing.c
> +++ b/drivers/hid/hid-winwing.c
> @@ -315,7 +315,8 @@ static void winwing_haptic_rumble_cb(struct work_struct *work)
>  static int winwing_play_effect(struct input_dev *dev, void *context,
>  		struct ff_effect *effect)
>  {
> -	struct winwing_drv_data *data = (struct winwing_drv_data *) context;
> +	struct hid_device *hdev = input_get_drvdata(dev);
> +	struct winwing_drv_data *data = hid_get_drvdata(hdev);
>  
>  	if (effect->type != FF_RUMBLE)
>  		return 0;
[ ... ]
> @@ -342,7 +343,12 @@ static int winwing_init_ff(struct hid_device *hdev, struct hid_input *hidinput)
>  
>  	input_set_capability(hidinput->input, EV_FF, FF_RUMBLE);
>  
> -	return input_ff_create_memless(hidinput->input, data,
> +	/*
> +	 * input_ff_create_memless() takes ownership of the context pointer
> +	 * and frees it on teardown; do not hand it the devm-managed drvdata.
> +	 * winwing_play_effect() fetches it from the input device instead.
> +	 */
> +	return input_ff_create_memless(hidinput->input, NULL,
>  			winwing_play_effect);
>  }

[Severity: High]
This is a pre-existing issue, but does the teardown ordering in
winwing_remove() in drivers/hid/hid-winwing.c cause rumble_work to be
re-queued after cancellation?

winwing_remove() {
	if (data)
		cancel_work_sync(&data->rumble_work);

	hid_hw_close(hdev);
	hid_hw_stop(hdev);
}

When hid_hw_stop() unregisters the input device, it invokes 
evdev_disconnect() and input_flush_device(). The flush executes
input_ff_flush(), which erases active effects by calling ff->playback()
with a magnitude of 0.

This triggers winwing_play_effect(), which re-schedules data->rumble_work
on the global workqueue. After winwing_remove() returns, devres frees the
data structure, leaving a pending work item that will access freed memory
when it runs.

Could this lead to a use-after-free?

[Severity: High]
This isn't a bug introduced by this patch, but is the lights_lock mutex in
struct winwing_drv_data used without ever being initialized?

In drivers/hid/hid-winwing.c:winwing_probe():
	data = devm_kzalloc(&hdev->dev, data_size, GFP_KERNEL);
	if (!data)
		return -ENOMEM;

The driver attempts to acquire this uninitialized mutex when userspace writes
to the LED brightness sysfs attribute:

drivers/hid/hid-winwing.c:winwing_led_write():
	mutex_lock(&data->lights_lock);

Can this cause a kernel crash or undefined behavior when lock contention
occurs?

[Severity: High]
This is a pre-existing issue, but do the LED class devices remain registered
after the hardware is stopped?

In drivers/hid/hid-winwing.c:winwing_remove():
	hid_hw_stop(hdev);

The underlying hardware is stopped here, but the devm-managed LEDs remain
registered until after this function returns and the driver's devres group
is released.

If userspace writes to the LED brightness attribute during the window between
hid_hw_stop() and devres cleanup, this triggers invalid hardware access on a
stopped transport:

drivers/hid/hid-winwing.c:winwing_led_write():
	ret = hid_hw_output_report(led->hdev, buf, 14);

Could this crash the kernel or cause a use-after-free in the low-level
transport driver?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=1