From febff2e1544b6555cc8a8e90697a975b78f4b901 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 27 Jun 2014 15:19:06 -0700 Subject: [PATCH] 3.4-stable patches 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.4/series | 2 + ...x-potential-blocked-i-o-after-resume.patch | 107 +++++++++++++++++ ...n-fix-potential-null-deref-at-resume.patch | 112 ++++++++++++++++++ 3 files changed, 221 insertions(+) create mode 100644 queue-3.4/usb-usb_wwan-fix-potential-blocked-i-o-after-resume.patch create mode 100644 queue-3.4/usb-usb_wwan-fix-potential-null-deref-at-resume.patch diff --git a/queue-3.4/series b/queue-3.4/series index 08b2f0ee6ef..254a5a70b66 100644 --- a/queue-3.4/series +++ b/queue-3.4/series @@ -19,3 +19,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.4/usb-usb_wwan-fix-potential-blocked-i-o-after-resume.patch b/queue-3.4/usb-usb_wwan-fix-potential-blocked-i-o-after-resume.patch new file mode 100644 index 00000000000..342f1e90dc0 --- /dev/null +++ b/queue-3.4/usb-usb_wwan-fix-potential-blocked-i-o-after-resume.patch @@ -0,0 +1,107 @@ +From fb7ad4f93d9f0f7d49beda32f5e7becb94b29a4d Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Mon, 26 May 2014 19:23:18 +0200 +Subject: USB: usb_wwan: fix potential blocked I/O after resume + +From: Johan Hovold + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + 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 +@@ -692,12 +692,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; +@@ -714,6 +714,8 @@ static void play_delayed(struct usb_seri + break; + } + } ++ ++ return err; + } + + int usb_wwan_resume(struct usb_serial *serial) +@@ -723,7 +725,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; + + dbg("%s entered", __func__); + +@@ -744,25 +747,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) { + err("%s: Error %d for bulk URB %d", + __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.4/usb-usb_wwan-fix-potential-null-deref-at-resume.patch b/queue-3.4/usb-usb_wwan-fix-potential-null-deref-at-resume.patch new file mode 100644 index 00000000000..4df65a14448 --- /dev/null +++ b/queue-3.4/usb-usb_wwan-fix-potential-null-deref-at-resume.patch @@ -0,0 +1,112 @@ +From 9096f1fbba916c2e052651e9de82fcfb98d4bea7 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Mon, 26 May 2014 19:23:17 +0200 +Subject: USB: usb_wwan: fix potential NULL-deref at resume + +From: Johan Hovold + +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 +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/usb_wwan.c | 42 ++++++++++++++++++++---------------------- + 1 file changed, 20 insertions(+), 22 deletions(-) + +--- a/drivers/usb/serial/usb_wwan.c ++++ b/drivers/usb/serial/usb_wwan.c +@@ -408,6 +408,14 @@ int usb_wwan_open(struct tty_struct *tty + + dbg("%s", __func__); + ++ 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]; +@@ -476,6 +484,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); + serial->interface->needs_remote_wakeup = 0; +@@ -551,7 +560,7 @@ static void usb_wwan_setup_urbs(struct u + + int usb_wwan_startup(struct usb_serial *serial) + { +- int i, j, err; ++ int i, j; + struct usb_serial_port *port; + struct usb_wwan_port_private *portdata; + u8 *buffer; +@@ -584,12 +593,6 @@ int usb_wwan_startup(struct usb_serial * + } + + usb_set_serial_port_data(port, portdata); +- +- if (!port->interrupt_in_urb) +- continue; +- err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); +- if (err) +- dbg("%s: submit irq_in urb failed %d", __func__, err); + } + usb_wwan_setup_urbs(serial); + return 0; +@@ -723,21 +726,6 @@ int usb_wwan_resume(struct usb_serial *s + int err = 0; + + dbg("%s entered", __func__); +- /* get the interrupt URBs resubmitted unconditionally */ +- for (i = 0; i < serial->num_ports; i++) { +- port = serial->port[i]; +- if (!port->interrupt_in_urb) { +- dbg("%s: No interrupt URB for port %d", __func__, i); +- continue; +- } +- err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); +- dbg("Submitted interrupt URB for port %d (result %d)", i, err); +- if (err < 0) { +- err("%s: Error %d for interrupt URB of port%d", +- __func__, err, i); +- goto err_out; +- } +- } + + spin_lock_irq(&intfdata->susp_lock); + for (i = 0; i < serial->num_ports; i++) { +@@ -749,6 +737,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); -- 2.47.3