patch "USB: yurex: fix NULL-derefs on disconnect" added to usb-linus
Subsystems (2)
This is a note to let you know that I've just added the patch titled
USB: yurex: fix NULL-derefs on disconnect
to my usb git tree which can be found at
git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git
in the usb-linus branch.
The patch will show up in the next release of the linux-next tree (usually sometime within the next 24 hours during the week.)
The patch will hopefully also be merged in Linus's tree for the next -rc kernel release.
If you have any questions about this process, please let me know.
From aafb00a977cf7d81821f7c9d12e04c558c22dc3c Mon Sep 17 00:00:00 2001
From: Johan Hovold <[email protected]>
Date: Wed, 9 Oct 2019 17:38:48 +0200
Subject: USB: yurex: fix NULL-derefs on disconnect
The driver was using its struct usb_interface pointer as an inverted disconnected flag, but was setting it to NULL without making sure all code paths that used it were done with it.
Before commit ef61eb43ada6 ("USB: yurex: Fix protection fault after device removal") this included the interrupt-in completion handler, but there are further accesses in dev_err and dev_dbg statements in yurex_write() and the driver-data destructor (sic!).
Fix this by unconditionally stopping also the control URB at disconnect and by using a dedicated disconnected flag.
Note that we need to take a reference to the struct usb_interface to avoid a use-after-free in the destructor whenever the device was disconnected while the character device was still open.
--- drivers/usb/misc/yurex.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/usb/misc/yurex.c +7 -4
@@ -60,6 +60,7 @@ struct usb_yurex {struct kref kref;struct mutex io_mutex; + unsigned long disconnected:1;struct fasync_struct *async_queue;wait_queue_head_t waitq;
@@ -107,6 +108,7 @@ static void yurex_delete(struct kref *kref) dev->int_buffer, dev->urb->transfer_dma);usb_free_urb (dev->urb); } +usb_put_intf (dev->interface);usb_put_dev (dev->udev);kfree (dev); }
@@ -205,7 +207,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_init_waitqueue_head (&dev->waitq); dev->udev =usb_get_dev (interface_to_usbdev (interface)); - dev->interface = interface; + dev->interface =usb_get_intf (interface);/* set up the endpoint information */ iface_desc = interface->cur_altsetting;
@@ -316,8 +318,9 @@ static void yurex_disconnect(struct usb_interface *interface)/* prevent more I/O from starting */ usb_poison_urb (dev->urb); +usb_poison_urb (dev->cntl_urb);mutex_lock (&dev->io_mutex); - dev->interface =NULL ; + dev->disconnected =1 ;mutex_unlock (&dev->io_mutex);/* wakeup waiters */
@@ -405,7 +408,7 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count, dev = file->private_data;mutex_lock (&dev->io_mutex); -if (!dev->interface) {/* already disconnected */ +if (dev->disconnected) {/* already disconnected */ mutex_unlock (&dev->io_mutex);return -ENODEV ; }
@@ -440,7 +443,7 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer, goto error;mutex_lock (&dev->io_mutex); -if (!dev->interface) {/* already disconnected */ +if (dev->disconnected) {/* already disconnected */ mutex_unlock (&dev->io_mutex); retval = -ENODEV ; goto error;
Signature · 1 line
2.23.0