FAILED: patch "[PATCH] USB: iowarrior: fix use-after-free on disconnect race" failed to apply to 5.10-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.10-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.10.y
git checkout FETCH_HEAD
git cherry-pick -x c602254ba4c10f60a73cd99d147874f86a3f485c
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026071456-raider-refocus-2e33@gregkh' --subject-prefix 'PATCH 5.10.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From c602254ba4c10f60a73cd99d147874f86a3f485c Mon Sep 17 00:00:00 2001
From: Johan Hovold <[email protected]>
Date: Mon, 22 Jun 2026 17:26:09 +0200
Subject: [PATCH] USB: iowarrior: fix use-after-free on disconnect race
mutex_unlock() may access the mutex structure after releasing the lock and therefore cannot be used to manage lifetime of objects directly (unlike spinlocks and refcounts). [1][2]
Use a kref to release the driver data to avoid use-after-free in mutex_unlock() when release() races with disconnect().
[1] a51749ab34d9 ("locking/mutex: Document that mutex_unlock() is non-atomic")
[2] 2b9d9e0a9ba0 ("locking/mutex: Clarify that mutex_unlock(), and most other sleeping locks, can still use the lock object after it's unlocked")
drivers/usb/misc/iowarrior.c +24 -33
@@ -72,6 +72,7 @@ static struct usb_driver iowarrior_driver;/* Structure to hold all of our device specific stuff */ struct iowarrior { +struct kref kref;struct mutex mutex;/* locks this structure */ struct usb_device *udev;/* save off the usb device pointer */ struct usb_interface *interface;/* the interface for this device */
@@ -240,8 +241,10 @@ static void iowarrior_write_callback(struct urb *urb)/* * iowarrior_delete */ -static inline void iowarrior_delete (struct iowarrior *dev) +static inline void iowarrior_delete (struct kref *kref) { + struct iowarrior *dev = container_of(kref, struct iowarrior, kref); +kfree (dev->int_in_buffer);usb_free_urb (dev->int_in_urb);kfree (dev->read_queue);
@@ -637,6 +640,9 @@ static int iowarrior_open(struct inode *inode, struct file *file) }/* increment our usage count for the driver */ ++dev->opened; + +kref_get (&dev->kref); +/* save our object in the file's private structure */ file->private_data = dev; retval =0 ;
@@ -652,7 +658,6 @@ static int iowarrior_open(struct inode *inode, struct file *file)static int iowarrior_release (struct inode *inode,struct file *file) {struct iowarrior *dev; -int retval =0 ; dev = file->private_data;if (!dev)
@@ -660,29 +665,18 @@ static int iowarrior_release(struct inode *inode, struct file *file)/* lock our device */ mutex_lock (&dev->mutex); + dev->opened =0 ;/* we're closing now */ -if (dev->opened <=0 ) { - retval = -ENODEV ;/* close called more than once */ -mutex_unlock (&dev->mutex); - }else { - dev->opened =0 ;/* we're closing now */ - retval =0 ; -if (dev->present) { -/* -The device is still connected so we only shutdown -pending read-/write-ops. -*/ -usb_kill_urb (dev->int_in_urb); -wake_up_interruptible (&dev->read_wait); -wake_up_interruptible (&dev->write_wait); -mutex_unlock (&dev->mutex); - }else { -/* The device was unplugged, cleanup resources */ -mutex_unlock (&dev->mutex); -iowarrior_delete (dev); - } +if (dev->present) { +usb_kill_urb (dev->int_in_urb); +wake_up_interruptible (&dev->read_wait); +wake_up_interruptible (&dev->write_wait); } -return retval; +mutex_unlock (&dev->mutex); + +kref_put (&dev->kref, iowarrior_delete); + +return 0 ; }static __poll_t iowarrior_poll (struct file *file,poll_table * wait)
@@ -767,6 +761,7 @@ static int iowarrior_probe(struct usb_interface *interface,if (!dev)return retval; +kref_init (&dev->kref);mutex_init (&dev->mutex);atomic_set (&dev->intr_idx,0 );
@@ -885,7 +880,8 @@ static int iowarrior_probe(struct usb_interface *interface,return retval; error: -iowarrior_delete (dev); +kref_put (&dev->kref, iowarrior_delete); +return retval; }
@@ -909,19 +905,14 @@ static void iowarrior_disconnect(struct usb_interface *interface)usb_kill_anchored_urbs (&dev->submitted);if (dev->opened) { -/* There is a process that holds a filedescriptor to the device , -so we only shutdown read-/write-ops going on. -Deleting the device is postponed until close() was called. -*/ usb_kill_urb (dev->int_in_urb);wake_up_interruptible (&dev->read_wait);wake_up_interruptible (&dev->write_wait); -mutex_unlock (&dev->mutex); - }else { -/* no process is using the device, cleanup now */ -mutex_unlock (&dev->mutex); -iowarrior_delete (dev); } + +mutex_unlock (&dev->mutex); + +kref_put (&dev->kref, iowarrior_delete); }/* usb specific object needed to register this driver with the usb subsystem */
Sasha Levin
maintainerPATCH 1/2 usb: iowarrior: remove inherent race with minor number
From: Oliver Neukum <[email protected]>
[ Upstream commit 56dd29088c9d9510c48a8ebad2465248fde36551 ]
The driver saves the minor number it gets upon registration in its descriptor for debugging purposes. However, there is inevitably a window between registration and saving the correct minor in a descriptor. During this window the debugging output will be wrong.
As wrong debug output is worse than no debug output, just remove it.
Stable-dep-of: c602254ba4c1 ("USB: iowarrior: fix use-after-free on disconnect race")
--- drivers/usb/misc/iowarrior.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-)
drivers/usb/misc/iowarrior.c +3 -14
@@ -74,7 +74,6 @@ struct iowarrior {struct mutex mutex;/* locks this structure */ struct usb_device *udev;/* save off the usb device pointer */ struct usb_interface *interface;/* the interface for this device */ -unsigned char minor;/* the starting minor number for this device */ struct usb_endpoint_descriptor *int_out_endpoint;/* endpoint for reading (needed for IOW56 only) */ struct usb_endpoint_descriptor *int_in_endpoint;/* endpoint for reading */ struct urb *int_in_urb;/* the urb for reading data */
@@ -246,7 +245,6 @@ static void iowarrior_write_callback(struct urb *urb)*/ static inline void iowarrior_delete (struct iowarrior *dev) { -dev_dbg (&dev->interface->dev,"minor %d\n" , dev->minor);kfree (dev->int_in_buffer);usb_free_urb (dev->int_in_urb);kfree (dev->read_queue);
@@ -297,9 +295,6 @@ static ssize_t iowarrior_read(struct file *file, char __user *buffer, goto exit; } -dev_dbg (&dev->interface->dev,"minor %d, count = %zd\n" , - dev->minor, count); -/* read count must be packet size (+ time stamp) */ if ((count != dev->report_size) && (count != (dev->report_size +1 ))) {
@@ -379,8 +374,6 @@ static ssize_t iowarrior_write(struct file *file, retval = -ENODEV ; goto exit; } -dev_dbg (&dev->interface->dev,"minor %d, count = %zd\n" , - dev->minor, count);/* if count is 0 we're already done */ if (count ==0 ) { retval =0 ;
@@ -526,9 +519,6 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd, goto error_out; } -dev_dbg (&dev->interface->dev,"minor %d, cmd 0x%.4x, arg %ld\n" , - dev->minor, cmd, arg); - retval =0 ; io_res =0 ;switch (cmd) {
@@ -675,8 +665,6 @@ static int iowarrior_release(struct inode *inode, struct file *file)if (!dev)return -ENODEV ; -dev_dbg (&dev->interface->dev,"minor %d\n" , dev->minor); -/* lock our device */ mutex_lock (&dev->mutex);
@@ -779,6 +767,7 @@ static int iowarrior_probe(struct usb_interface *interface,struct usb_host_interface *iface_desc;int retval = -ENOMEM ;int res; +int minor;/* allocate memory for our device state and initialize it */ dev =kzalloc (sizeof (struct iowarrior ),GFP_KERNEL );
@@ -894,12 +883,12 @@ static int iowarrior_probe(struct usb_interface *interface, goto error; } - dev->minor = interface->minor; + minor = interface->minor;/* let the user know what node this device is now attached to */ dev_info (&interface->dev,"IOWarrior product=0x%x, serial=%s interface=%d " "now attached to iowarrior%d\n" , dev->product_id, dev->chip_serial, - iface_desc->desc.bInterfaceNumber, dev->minor -IOWARRIOR_MINOR_BASE ); + iface_desc->desc.bInterfaceNumber, minor -IOWARRIOR_MINOR_BASE );return retval; error:
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/2 USB: iowarrior: fix use-after-free on disconnect race
From: Johan Hovold <[email protected]>
[ Upstream commit c602254ba4c10f60a73cd99d147874f86a3f485c ]
mutex_unlock() may access the mutex structure after releasing the lock and therefore cannot be used to manage lifetime of objects directly (unlike spinlocks and refcounts). [1][2]
Use a kref to release the driver data to avoid use-after-free in mutex_unlock() when release() races with disconnect().
[1] a51749ab34d9 ("locking/mutex: Document that mutex_unlock() is non-atomic")
[2] 2b9d9e0a9ba0 ("locking/mutex: Clarify that mutex_unlock(), and most other sleeping locks, can still use the lock object after it's unlocked")
--- drivers/usb/misc/iowarrior.c | 57 +++++++++++++++--------------------- 1 file changed, 24 insertions(+), 33 deletions(-)
drivers/usb/misc/iowarrior.c +24 -33
@@ -71,6 +71,7 @@ static struct usb_driver iowarrior_driver;/* Structure to hold all of our device specific stuff */ struct iowarrior { +struct kref kref;struct mutex mutex;/* locks this structure */ struct usb_device *udev;/* save off the usb device pointer */ struct usb_interface *interface;/* the interface for this device */
@@ -243,8 +244,10 @@ static void iowarrior_write_callback(struct urb *urb)/* * iowarrior_delete */ -static inline void iowarrior_delete (struct iowarrior *dev) +static inline void iowarrior_delete (struct kref *kref) { + struct iowarrior *dev = container_of(kref, struct iowarrior, kref); +kfree (dev->int_in_buffer);usb_free_urb (dev->int_in_urb);kfree (dev->read_queue);
@@ -644,6 +647,9 @@ static int iowarrior_open(struct inode *inode, struct file *file) }/* increment our usage count for the driver */ ++dev->opened; + +kref_get (&dev->kref); +/* save our object in the file's private structure */ file->private_data = dev; retval =0 ;
@@ -659,7 +665,6 @@ static int iowarrior_open(struct inode *inode, struct file *file)static int iowarrior_release (struct inode *inode,struct file *file) {struct iowarrior *dev; -int retval =0 ; dev = file->private_data;if (!dev)
@@ -667,29 +672,18 @@ static int iowarrior_release(struct inode *inode, struct file *file)/* lock our device */ mutex_lock (&dev->mutex); + dev->opened =0 ;/* we're closing now */ -if (dev->opened <=0 ) { - retval = -ENODEV ;/* close called more than once */ -mutex_unlock (&dev->mutex); - }else { - dev->opened =0 ;/* we're closing now */ - retval =0 ; -if (dev->present) { -/* -The device is still connected so we only shutdown -pending read-/write-ops. -*/ -usb_kill_urb (dev->int_in_urb); -wake_up_interruptible (&dev->read_wait); -wake_up_interruptible (&dev->write_wait); -mutex_unlock (&dev->mutex); - }else { -/* The device was unplugged, cleanup resources */ -mutex_unlock (&dev->mutex); -iowarrior_delete (dev); - } +if (dev->present) { +usb_kill_urb (dev->int_in_urb); +wake_up_interruptible (&dev->read_wait); +wake_up_interruptible (&dev->write_wait); } -return retval; +mutex_unlock (&dev->mutex); + +kref_put (&dev->kref, iowarrior_delete); + +return 0 ; }static __poll_t iowarrior_poll (struct file *file,poll_table * wait)
@@ -774,6 +768,7 @@ static int iowarrior_probe(struct usb_interface *interface,if (!dev)return retval; +kref_init (&dev->kref);mutex_init (&dev->mutex);atomic_set (&dev->intr_idx,0 );
@@ -892,7 +887,8 @@ static int iowarrior_probe(struct usb_interface *interface,return retval; error: -iowarrior_delete (dev); +kref_put (&dev->kref, iowarrior_delete); +return retval; }
@@ -913,20 +909,15 @@ static void iowarrior_disconnect(struct usb_interface *interface) dev->present =0 ;if (dev->opened) { -/* There is a process that holds a filedescriptor to the device , -so we only shutdown read-/write-ops going on. -Deleting the device is postponed until close() was called. -*/ usb_kill_urb (dev->int_in_urb);usb_kill_anchored_urbs (&dev->submitted);wake_up_interruptible (&dev->read_wait);wake_up_interruptible (&dev->write_wait); -mutex_unlock (&dev->mutex); - }else { -/* no process is using the device, cleanup now */ -mutex_unlock (&dev->mutex); -iowarrior_delete (dev); } + +mutex_unlock (&dev->mutex); + +kref_put (&dev->kref, iowarrior_delete); }/* usb specific object needed to register this driver with the usb subsystem */
Signature · 1 line
2.53.0