[PATCH] Input: xpad - fix use-after-free in probe error path

From: Zhang Shurong

Date: Fri Nov 06 2026 - 10:43:12 EST


xpad_probe() creates the input device asynchronously for wireless
(XTYPE_XBOX360W) controllers: xpad360w_start_input() submits the interrupt
URB, and its completion handler queues xpad->work, which calls
xpad_init_input() and registers the input device. It then submits a
presence packet on the output URB; if that submission fails,
xpad360w_start_input() returns an error after the interrupt URB has
already been submitted and may have completed. The err_deinit_output
label then only tears down the output URBs and frees the xpad structure.
It never cancels the pending work nor unregisters an input device that the
work may already have created.

Consequently, after kfree(xpad) the input device can remain registered and
input_dev->phys still points into the freed xpad->phys[64] array. A
userspace EVIOCGPHYS ioctl on the corresponding event node then reads the
dangling pointer:

BUG: KASAN: slab-use-after-free in strlen
Read of size 1 at ...
Call Trace:
strlen
str_to_user
evdev_do_ioctl
evdev_ioctl
__x64_sys_ioctl

The same window also allows the queued work or the output URB callbacks to
run after xpad has been freed, which can instead report a use-after-free in
xpad_init_input() or xpad_prepare_next_out_packet().

Make the error path mirror xpad_disconnect(): stop the wireless input URB
(which also flushes the queued work), unregister the input device if it was
created, stop the output URB, release the output resources, and clear the
interface data before freeing the xpad structure.

This use-after-free has been reproduced and the fix has been verified on a
KASAN-enabled kernel. The original syzbot report's allocation and free
stacks show the address later reused by tmpfs; the xpad owner was
established by local reproduction.

Fixes: 09c8b00ae3e1 ("Input: xpad - handle "present" and "gone" correctly")
Link: https://syzkaller.appspot.com/bug?id=04f471e8f027835f49842bbc7694e723d2289d7d
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Zhang Shurong <zhang_shurong@xxxxxxxxxxx>
---
drivers/input/joystick/xpad.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 53fd3b562f41..3951b4b05740 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -2224,7 +2224,12 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
return 0;

err_deinit_output:
+ if (xpad->xtype == XTYPE_XBOX360W)
+ xpad360w_stop_input(xpad);
+ xpad_deinit_input(xpad);
+ xpad_stop_output(xpad);
xpad_deinit_output(xpad);
+ usb_set_intfdata(intf, NULL);
err_free_in_urb:
usb_free_urb(xpad->irq_in);
err_free_idata:
--
2.39.5