Home Home > GIT Browse > SLE12-SP4
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver Neukum <oneukum@suse.com>2019-10-16 15:14:01 +0200
committerOliver Neukum <oneukum@suse.com>2019-10-16 15:14:01 +0200
commit6eede1b2690d09d5f220db862c693287f0b79a1c (patch)
tree5a24f02f97c3a7b9cba34db4ec5289ab9a9c1add
parenta71bb8f088901d68818b62cc7536b44d6d945cec (diff)
USB: usblcd: fix I/O after disconnect (bsc#1142635).
-rw-r--r--patches.suse/0001-USB-usblcd-fix-I-O-after-disconnect.patch132
-rw-r--r--series.conf1
2 files changed, 133 insertions, 0 deletions
diff --git a/patches.suse/0001-USB-usblcd-fix-I-O-after-disconnect.patch b/patches.suse/0001-USB-usblcd-fix-I-O-after-disconnect.patch
new file mode 100644
index 0000000000..3dec9c0545
--- /dev/null
+++ b/patches.suse/0001-USB-usblcd-fix-I-O-after-disconnect.patch
@@ -0,0 +1,132 @@
+From eb7f5a490c5edfe8126f64bc58b9ba2edef0a425 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <johan@kernel.org>
+Date: Thu, 26 Sep 2019 11:12:25 +0200
+Subject: [PATCH] USB: usblcd: fix I/O after disconnect
+Git-commit: eb7f5a490c5edfe8126f64bc58b9ba2edef0a425
+Patch-mainline: v5.4-rc3
+References: bsc#1142635
+
+Make sure to stop all I/O on disconnect by adding a disconnected flag
+which is used to prevent new I/O from being started and by stopping all
+ongoing I/O before returning.
+
+This also fixes a potential use-after-free on driver unbind in case the
+driver data is freed before the completion handler has run.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Cc: stable <stable@vger.kernel.org> # 7bbe990c989e
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Link: https://lore.kernel.org/r/20190926091228.24634-7-johan@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Oliver Neukum <oneukum@suse.com>
+---
+ drivers/usb/misc/usblcd.c | 33 +++++++++++++++++++++++++++++++--
+ 1 file changed, 31 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
+index 9ba4a4e68d91..aa982d3ca36b 100644
+--- a/drivers/usb/misc/usblcd.c
++++ b/drivers/usb/misc/usblcd.c
+@@ -18,6 +18,7 @@
+ #include <linux/slab.h>
+ #include <linux/errno.h>
+ #include <linux/mutex.h>
++#include <linux/rwsem.h>
+ #include <linux/uaccess.h>
+ #include <linux/usb.h>
+
+@@ -57,6 +58,8 @@ struct usb_lcd {
+ using up all RAM */
+ struct usb_anchor submitted; /* URBs to wait for
+ before suspend */
++ struct rw_semaphore io_rwsem;
++ unsigned long disconnected:1;
+ };
+ #define to_lcd_dev(d) container_of(d, struct usb_lcd, kref)
+
+@@ -142,6 +145,13 @@ static ssize_t lcd_read(struct file *file, char __user * buffer,
+
+ dev = file->private_data;
+
++ down_read(&dev->io_rwsem);
++
++ if (dev->disconnected) {
++ retval = -ENODEV;
++ goto out_up_io;
++ }
++
+ /* do a blocking bulk read to get data from the device */
+ retval = usb_bulk_msg(dev->udev,
+ usb_rcvbulkpipe(dev->udev,
+@@ -158,6 +168,9 @@ static ssize_t lcd_read(struct file *file, char __user * buffer,
+ retval = bytes_read;
+ }
+
++out_up_io:
++ up_read(&dev->io_rwsem);
++
+ return retval;
+ }
+
+@@ -237,11 +250,18 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer,
+ if (r < 0)
+ return -EINTR;
+
++ down_read(&dev->io_rwsem);
++
++ if (dev->disconnected) {
++ retval = -ENODEV;
++ goto err_up_io;
++ }
++
+ /* create a urb, and a buffer for it, and copy the data to the urb */
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ retval = -ENOMEM;
+- goto err_no_buf;
++ goto err_up_io;
+ }
+
+ buf = usb_alloc_coherent(dev->udev, count, GFP_KERNEL,
+@@ -278,6 +298,7 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer,
+ the USB core will eventually free it entirely */
+ usb_free_urb(urb);
+
++ up_read(&dev->io_rwsem);
+ exit:
+ return count;
+ error_unanchor:
+@@ -285,7 +306,8 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer,
+ error:
+ usb_free_coherent(dev->udev, count, buf, urb->transfer_dma);
+ usb_free_urb(urb);
+-err_no_buf:
++err_up_io:
++ up_read(&dev->io_rwsem);
+ up(&dev->limit_sem);
+ return retval;
+ }
+@@ -325,6 +347,7 @@ static int lcd_probe(struct usb_interface *interface,
+
+ kref_init(&dev->kref);
+ sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES);
++ init_rwsem(&dev->io_rwsem);
+ init_usb_anchor(&dev->submitted);
+
+ dev->udev = usb_get_dev(interface_to_usbdev(interface));
+@@ -422,6 +445,12 @@ static void lcd_disconnect(struct usb_interface *interface)
+ /* give back our minor */
+ usb_deregister_dev(interface, &lcd_class);
+
++ down_write(&dev->io_rwsem);
++ dev->disconnected = 1;
++ up_write(&dev->io_rwsem);
++
++ usb_kill_anchored_urbs(&dev->submitted);
++
+ /* decrement our usage count */
+ kref_put(&dev->kref, lcd_delete);
+
+--
+2.16.4
+
diff --git a/series.conf b/series.conf
index a411d06cde..fafbd21443 100644
--- a/series.conf
+++ b/series.conf
@@ -24764,6 +24764,7 @@
patches.suse/0001-USB-microtek-fix-info-leak-at-probe.patch
patches.suse/0001-USB-adutux-fix-use-after-free-on-disconnect.patch
patches.suse/0001-USB-adutux-fix-NULL-derefs-on-disconnect.patch
+ patches.suse/0001-USB-usblcd-fix-I-O-after-disconnect.patch
# davem/net
patches.suse/net-ibmvnic-Fix-EOI-when-running-in-XIVE-mode.patch