aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial
diff options
context:
space:
mode:
authorJohan Hovold <jhovold@gmail.com>2014-05-26 13:23:17 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-05-27 18:04:06 -0400
commit9096f1fbba916c2e052651e9de82fcfb98d4bea7 (patch)
treedb0db9168fd162bc424e8e37156783681e36580f /drivers/usb/serial
parent79eed03e77d481b55d85d1cfe5a1636a0d3897fd (diff)
USB: usb_wwan: fix potential NULL-deref at resume
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") Cc: <stable@vger.kernel.org> # v2.6.32: 032129cb03df Signed-off-by: Johan Hovold <jhovold@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/serial')
-rw-r--r--drivers/usb/serial/usb_wwan.c43
1 files changed, 19 insertions, 24 deletions
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 2ab478b55759..c5b9deb2e04e 100644
--- 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, struct usb_serial_port *port)
388 portdata = usb_get_serial_port_data(port); 388 portdata = usb_get_serial_port_data(port);
389 intfdata = serial->private; 389 intfdata = serial->private;
390 390
391 if (port->interrupt_in_urb) {
392 err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
393 if (err) {
394 dev_dbg(&port->dev, "%s: submit int urb failed: %d\n",
395 __func__, err);
396 }
397 }
398
391 /* Start reading from the IN endpoint */ 399 /* Start reading from the IN endpoint */
392 for (i = 0; i < N_IN_URB; i++) { 400 for (i = 0; i < N_IN_URB; i++) {
393 urb = portdata->in_urbs[i]; 401 urb = portdata->in_urbs[i];
@@ -454,6 +462,7 @@ void usb_wwan_close(struct usb_serial_port *port)
454 usb_kill_urb(portdata->in_urbs[i]); 462 usb_kill_urb(portdata->in_urbs[i]);
455 for (i = 0; i < N_OUT_URB; i++) 463 for (i = 0; i < N_OUT_URB; i++)
456 usb_kill_urb(portdata->out_urbs[i]); 464 usb_kill_urb(portdata->out_urbs[i]);
465 usb_kill_urb(port->interrupt_in_urb);
457 466
458 /* balancing - important as an error cannot be handled*/ 467 /* balancing - important as an error cannot be handled*/
459 usb_autopm_get_interface_no_resume(serial->interface); 468 usb_autopm_get_interface_no_resume(serial->interface);
@@ -487,7 +496,6 @@ int usb_wwan_port_probe(struct usb_serial_port *port)
487 struct usb_wwan_port_private *portdata; 496 struct usb_wwan_port_private *portdata;
488 struct urb *urb; 497 struct urb *urb;
489 u8 *buffer; 498 u8 *buffer;
490 int err;
491 int i; 499 int i;
492 500
493 if (!port->bulk_in_size || !port->bulk_out_size) 501 if (!port->bulk_in_size || !port->bulk_out_size)
@@ -527,13 +535,6 @@ int usb_wwan_port_probe(struct usb_serial_port *port)
527 535
528 usb_set_serial_port_data(port, portdata); 536 usb_set_serial_port_data(port, portdata);
529 537
530 if (port->interrupt_in_urb) {
531 err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
532 if (err)
533 dev_dbg(&port->dev, "%s: submit irq_in urb failed %d\n",
534 __func__, err);
535 }
536
537 return 0; 538 return 0;
538 539
539bail_out_error2: 540bail_out_error2:
@@ -651,22 +652,6 @@ int usb_wwan_resume(struct usb_serial *serial)
651 struct urb *urb; 652 struct urb *urb;
652 int err = 0; 653 int err = 0;
653 654
654 /* get the interrupt URBs resubmitted unconditionally */
655 for (i = 0; i < serial->num_ports; i++) {
656 port = serial->port[i];
657 if (!port->interrupt_in_urb) {
658 dev_dbg(&port->dev, "%s: No interrupt URB for port\n", __func__);
659 continue;
660 }
661 err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
662 dev_dbg(&port->dev, "Submitted interrupt URB for port (result %d)\n", err);
663 if (err < 0) {
664 dev_err(&port->dev, "%s: Error %d for interrupt URB\n",
665 __func__, err);
666 goto err_out;
667 }
668 }
669
670 spin_lock_irq(&intfdata->susp_lock); 655 spin_lock_irq(&intfdata->susp_lock);
671 for (i = 0; i < serial->num_ports; i++) { 656 for (i = 0; i < serial->num_ports; i++) {
672 /* walk all ports */ 657 /* walk all ports */
@@ -677,6 +662,16 @@ int usb_wwan_resume(struct usb_serial *serial)
677 if (!portdata || !portdata->opened) 662 if (!portdata || !portdata->opened)
678 continue; 663 continue;
679 664
665 if (port->interrupt_in_urb) {
666 err = usb_submit_urb(port->interrupt_in_urb,
667 GFP_ATOMIC);
668 if (err) {
669 dev_err(&port->dev,
670 "%s: submit int urb failed: %d\n",
671 __func__, err);
672 }
673 }
674
680 for (j = 0; j < N_IN_URB; j++) { 675 for (j = 0; j < N_IN_URB; j++) {
681 urb = portdata->in_urbs[j]; 676 urb = portdata->in_urbs[j];
682 err = usb_submit_urb(urb, GFP_ATOMIC); 677 err = usb_submit_urb(urb, GFP_ATOMIC);