Commit 571a1406 authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman

USB: yurex: fix NULL-derefs on disconnect

commit aafb00a9 upstream.

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 ef61eb43 ("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.

Fixes: aadd6472 ("USB: yurex.c: remove dbg() usage")
Fixes: 45714104 ("USB: yurex.c: remove err() usage")
Cc: stable <stable@vger.kernel.org>     # 3.5: ef61eb43Signed-off-by: default avatarJohan Hovold <johan@kernel.org>
Link: https://lore.kernel.org/r/20191009153848.8664-6-johan@kernel.orgSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent a8fe336f
...@@ -60,6 +60,7 @@ struct usb_yurex { ...@@ -60,6 +60,7 @@ struct usb_yurex {
struct kref kref; struct kref kref;
struct mutex io_mutex; struct mutex io_mutex;
unsigned long disconnected:1;
struct fasync_struct *async_queue; struct fasync_struct *async_queue;
wait_queue_head_t waitq; wait_queue_head_t waitq;
...@@ -107,6 +108,7 @@ static void yurex_delete(struct kref *kref) ...@@ -107,6 +108,7 @@ static void yurex_delete(struct kref *kref)
dev->int_buffer, dev->urb->transfer_dma); dev->int_buffer, dev->urb->transfer_dma);
usb_free_urb(dev->urb); usb_free_urb(dev->urb);
} }
usb_put_intf(dev->interface);
usb_put_dev(dev->udev); usb_put_dev(dev->udev);
kfree(dev); kfree(dev);
} }
...@@ -205,7 +207,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ ...@@ -205,7 +207,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
init_waitqueue_head(&dev->waitq); init_waitqueue_head(&dev->waitq);
dev->udev = usb_get_dev(interface_to_usbdev(interface)); dev->udev = usb_get_dev(interface_to_usbdev(interface));
dev->interface = interface; dev->interface = usb_get_intf(interface);
/* set up the endpoint information */ /* set up the endpoint information */
iface_desc = interface->cur_altsetting; iface_desc = interface->cur_altsetting;
...@@ -316,8 +318,9 @@ static void yurex_disconnect(struct usb_interface *interface) ...@@ -316,8 +318,9 @@ static void yurex_disconnect(struct usb_interface *interface)
/* prevent more I/O from starting */ /* prevent more I/O from starting */
usb_poison_urb(dev->urb); usb_poison_urb(dev->urb);
usb_poison_urb(dev->cntl_urb);
mutex_lock(&dev->io_mutex); mutex_lock(&dev->io_mutex);
dev->interface = NULL; dev->disconnected = 1;
mutex_unlock(&dev->io_mutex); mutex_unlock(&dev->io_mutex);
/* wakeup waiters */ /* wakeup waiters */
...@@ -405,7 +408,7 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count, ...@@ -405,7 +408,7 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
dev = file->private_data; dev = file->private_data;
mutex_lock(&dev->io_mutex); mutex_lock(&dev->io_mutex);
if (!dev->interface) { /* already disconnected */ if (dev->disconnected) { /* already disconnected */
mutex_unlock(&dev->io_mutex); mutex_unlock(&dev->io_mutex);
return -ENODEV; return -ENODEV;
} }
...@@ -440,7 +443,7 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer, ...@@ -440,7 +443,7 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer,
goto error; goto error;
mutex_lock(&dev->io_mutex); mutex_lock(&dev->io_mutex);
if (!dev->interface) { /* already disconnected */ if (dev->disconnected) { /* already disconnected */
mutex_unlock(&dev->io_mutex); mutex_unlock(&dev->io_mutex);
retval = -ENODEV; retval = -ENODEV;
goto error; goto error;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment