]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 27 Jun 2014 22:19:33 +0000 (15:19 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 27 Jun 2014 22:19:33 +0000 (15:19 -0700)
added patches:
usb-usb_wwan-fix-potential-blocked-i-o-after-resume.patch
usb-usb_wwan-fix-potential-null-deref-at-resume.patch

queue-3.10/series
queue-3.10/usb-usb_wwan-fix-potential-blocked-i-o-after-resume.patch [new file with mode: 0644]
queue-3.10/usb-usb_wwan-fix-potential-null-deref-at-resume.patch [new file with mode: 0644]

index 4b8bd965613de373e981c2b7de83ab830402c6e4..d003c06326bce559b67bd90c5d81331358968edb 100644 (file)
@@ -28,3 +28,5 @@ usb-usb_wwan-fix-urb-leak-in-write-error-path.patch
 usb-usb_wwan-fix-race-between-write-and-resume.patch
 usb-usb_wwan-fix-write-and-suspend-race.patch
 usb-usb_wwan-fix-urb-leak-at-shutdown.patch
+usb-usb_wwan-fix-potential-null-deref-at-resume.patch
+usb-usb_wwan-fix-potential-blocked-i-o-after-resume.patch
diff --git a/queue-3.10/usb-usb_wwan-fix-potential-blocked-i-o-after-resume.patch b/queue-3.10/usb-usb_wwan-fix-potential-blocked-i-o-after-resume.patch
new file mode 100644 (file)
index 0000000..4f25654
--- /dev/null
@@ -0,0 +1,107 @@
+From fb7ad4f93d9f0f7d49beda32f5e7becb94b29a4d Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Mon, 26 May 2014 19:23:18 +0200
+Subject: USB: usb_wwan: fix potential blocked I/O after resume
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit fb7ad4f93d9f0f7d49beda32f5e7becb94b29a4d upstream.
+
+Keep trying to submit urbs rather than bail out on first read-urb
+submission error, which would also prevent I/O for any further ports
+from being resumed.
+
+Instead keep an error count, for all types of failed submissions, and
+let USB core know that something went wrong.
+
+Also make sure to always clear the suspended flag. Currently a failed
+read-urb submission would prevent cached writes as well as any
+subsequent writes from being submitted until next suspend-resume cycle,
+something which may not even necessarily happen.
+
+Note that USB core currently only logs an error if an interface resume
+failed.
+
+Fixes: 383cedc3bb43 ("USB: serial: full autosuspend support for the
+option driver")
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/usb_wwan.c |   25 +++++++++++++++++--------
+ 1 file changed, 17 insertions(+), 8 deletions(-)
+
+--- a/drivers/usb/serial/usb_wwan.c
++++ b/drivers/usb/serial/usb_wwan.c
+@@ -623,12 +623,12 @@ int usb_wwan_suspend(struct usb_serial *
+ }
+ EXPORT_SYMBOL(usb_wwan_suspend);
+-static void play_delayed(struct usb_serial_port *port)
++static int play_delayed(struct usb_serial_port *port)
+ {
+       struct usb_wwan_intf_private *data;
+       struct usb_wwan_port_private *portdata;
+       struct urb *urb;
+-      int err;
++      int err = 0;
+       portdata = usb_get_serial_port_data(port);
+       data = port->serial->private;
+@@ -645,6 +645,8 @@ static void play_delayed(struct usb_seri
+                       break;
+               }
+       }
++
++      return err;
+ }
+ int usb_wwan_resume(struct usb_serial *serial)
+@@ -654,7 +656,8 @@ int usb_wwan_resume(struct usb_serial *s
+       struct usb_wwan_intf_private *intfdata = serial->private;
+       struct usb_wwan_port_private *portdata;
+       struct urb *urb;
+-      int err = 0;
++      int err;
++      int err_count = 0;
+       spin_lock_irq(&intfdata->susp_lock);
+       for (i = 0; i < serial->num_ports; i++) {
+@@ -673,25 +676,31 @@ int usb_wwan_resume(struct usb_serial *s
+                               dev_err(&port->dev,
+                                       "%s: submit int urb failed: %d\n",
+                                       __func__, err);
++                              err_count++;
+                       }
+               }
++              err = play_delayed(port);
++              if (err)
++                      err_count++;
++
+               for (j = 0; j < N_IN_URB; j++) {
+                       urb = portdata->in_urbs[j];
+                       err = usb_submit_urb(urb, GFP_ATOMIC);
+                       if (err < 0) {
+                               dev_err(&port->dev, "%s: Error %d for bulk URB %d\n",
+                                       __func__, err, i);
+-                              spin_unlock_irq(&intfdata->susp_lock);
+-                              goto err_out;
++                              err_count++;
+                       }
+               }
+-              play_delayed(port);
+       }
+       intfdata->suspended = 0;
+       spin_unlock_irq(&intfdata->susp_lock);
+-err_out:
+-      return err;
++
++      if (err_count)
++              return -EIO;
++
++      return 0;
+ }
+ EXPORT_SYMBOL(usb_wwan_resume);
+ #endif
diff --git a/queue-3.10/usb-usb_wwan-fix-potential-null-deref-at-resume.patch b/queue-3.10/usb-usb_wwan-fix-potential-null-deref-at-resume.patch
new file mode 100644 (file)
index 0000000..1aa5f71
--- /dev/null
@@ -0,0 +1,113 @@
+From 9096f1fbba916c2e052651e9de82fcfb98d4bea7 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <jhovold@gmail.com>
+Date: Mon, 26 May 2014 19:23:17 +0200
+Subject: USB: usb_wwan: fix potential NULL-deref at resume
+
+From: Johan Hovold <jhovold@gmail.com>
+
+commit 9096f1fbba916c2e052651e9de82fcfb98d4bea7 upstream.
+
+The interrupt urb was submitted unconditionally at resume, something
+which could lead to a NULL-pointer dereference in the urb completion
+handler as resume may be called after the port and port data is gone.
+
+Fix this by making sure the interrupt urb is only submitted and active
+when the port is open.
+
+Fixes: 383cedc3bb43 ("USB: serial: full autosuspend support for the
+option driver")
+
+Signed-off-by: Johan Hovold <jhovold@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/usb_wwan.c |   43 ++++++++++++++++++------------------------
+ 1 file changed, 19 insertions(+), 24 deletions(-)
+
+--- a/drivers/usb/serial/usb_wwan.c
++++ b/drivers/usb/serial/usb_wwan.c
+@@ -388,6 +388,14 @@ int usb_wwan_open(struct tty_struct *tty
+       portdata = usb_get_serial_port_data(port);
+       intfdata = serial->private;
++      if (port->interrupt_in_urb) {
++              err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
++              if (err) {
++                      dev_dbg(&port->dev, "%s: submit int urb failed: %d\n",
++                              __func__, err);
++              }
++      }
++
+       /* Start reading from the IN endpoint */
+       for (i = 0; i < N_IN_URB; i++) {
+               urb = portdata->in_urbs[i];
+@@ -454,6 +462,7 @@ void usb_wwan_close(struct usb_serial_po
+               usb_kill_urb(portdata->in_urbs[i]);
+       for (i = 0; i < N_OUT_URB; i++)
+               usb_kill_urb(portdata->out_urbs[i]);
++      usb_kill_urb(port->interrupt_in_urb);
+       /* balancing - important as an error cannot be handled*/
+       usb_autopm_get_interface_no_resume(serial->interface);
+@@ -491,7 +500,6 @@ int usb_wwan_port_probe(struct usb_seria
+       struct usb_wwan_port_private *portdata;
+       struct urb *urb;
+       u8 *buffer;
+-      int err;
+       int i;
+       if (!port->bulk_in_size || !port->bulk_out_size)
+@@ -531,13 +539,6 @@ int usb_wwan_port_probe(struct usb_seria
+       usb_set_serial_port_data(port, portdata);
+-      if (port->interrupt_in_urb) {
+-              err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+-              if (err)
+-                      dev_dbg(&port->dev, "%s: submit irq_in urb failed %d\n",
+-                              __func__, err);
+-      }
+-
+       return 0;
+ bail_out_error2:
+@@ -655,22 +656,6 @@ int usb_wwan_resume(struct usb_serial *s
+       struct urb *urb;
+       int err = 0;
+-      /* get the interrupt URBs resubmitted unconditionally */
+-      for (i = 0; i < serial->num_ports; i++) {
+-              port = serial->port[i];
+-              if (!port->interrupt_in_urb) {
+-                      dev_dbg(&port->dev, "%s: No interrupt URB for port\n", __func__);
+-                      continue;
+-              }
+-              err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
+-              dev_dbg(&port->dev, "Submitted interrupt URB for port (result %d)\n", err);
+-              if (err < 0) {
+-                      dev_err(&port->dev, "%s: Error %d for interrupt URB\n",
+-                              __func__, err);
+-                      goto err_out;
+-              }
+-      }
+-
+       spin_lock_irq(&intfdata->susp_lock);
+       for (i = 0; i < serial->num_ports; i++) {
+               /* walk all ports */
+@@ -681,6 +666,16 @@ int usb_wwan_resume(struct usb_serial *s
+               if (!portdata || !portdata->opened)
+                       continue;
++              if (port->interrupt_in_urb) {
++                      err = usb_submit_urb(port->interrupt_in_urb,
++                                      GFP_ATOMIC);
++                      if (err) {
++                              dev_err(&port->dev,
++                                      "%s: submit int urb failed: %d\n",
++                                      __func__, err);
++                      }
++              }
++
+               for (j = 0; j < N_IN_URB; j++) {
+                       urb = portdata->in_urbs[j];
+                       err = usb_submit_urb(urb, GFP_ATOMIC);