Commit 0886f4e9 authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman

USB: usb_wwan: fix potential NULL-deref at resume

commit 9096f1fb 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: 383cedc3 ("USB: serial: full autosuspend support for the
option driver")
Signed-off-by: default avatarJohan Hovold <jhovold@gmail.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent ca91395e
...@@ -408,6 +408,14 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port) ...@@ -408,6 +408,14 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)
dbg("%s", __func__); 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 */ /* Start reading from the IN endpoint */
for (i = 0; i < N_IN_URB; i++) { for (i = 0; i < N_IN_URB; i++) {
urb = portdata->in_urbs[i]; urb = portdata->in_urbs[i];
...@@ -476,6 +484,7 @@ void usb_wwan_close(struct usb_serial_port *port) ...@@ -476,6 +484,7 @@ void usb_wwan_close(struct usb_serial_port *port)
usb_kill_urb(portdata->in_urbs[i]); usb_kill_urb(portdata->in_urbs[i]);
for (i = 0; i < N_OUT_URB; i++) for (i = 0; i < N_OUT_URB; i++)
usb_kill_urb(portdata->out_urbs[i]); usb_kill_urb(portdata->out_urbs[i]);
usb_kill_urb(port->interrupt_in_urb);
/* balancing - important as an error cannot be handled*/ /* balancing - important as an error cannot be handled*/
usb_autopm_get_interface_no_resume(serial->interface); usb_autopm_get_interface_no_resume(serial->interface);
serial->interface->needs_remote_wakeup = 0; serial->interface->needs_remote_wakeup = 0;
...@@ -551,7 +560,7 @@ static void usb_wwan_setup_urbs(struct usb_serial *serial) ...@@ -551,7 +560,7 @@ static void usb_wwan_setup_urbs(struct usb_serial *serial)
int usb_wwan_startup(struct usb_serial *serial) int usb_wwan_startup(struct usb_serial *serial)
{ {
int i, j, err; int i, j;
struct usb_serial_port *port; struct usb_serial_port *port;
struct usb_wwan_port_private *portdata; struct usb_wwan_port_private *portdata;
u8 *buffer; u8 *buffer;
...@@ -584,12 +593,6 @@ int usb_wwan_startup(struct usb_serial *serial) ...@@ -584,12 +593,6 @@ int usb_wwan_startup(struct usb_serial *serial)
} }
usb_set_serial_port_data(port, portdata); 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); usb_wwan_setup_urbs(serial);
return 0; return 0;
...@@ -723,21 +726,6 @@ int usb_wwan_resume(struct usb_serial *serial) ...@@ -723,21 +726,6 @@ int usb_wwan_resume(struct usb_serial *serial)
int err = 0; int err = 0;
dbg("%s entered", __func__); 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); spin_lock_irq(&intfdata->susp_lock);
for (i = 0; i < serial->num_ports; i++) { for (i = 0; i < serial->num_ports; i++) {
...@@ -749,6 +737,16 @@ int usb_wwan_resume(struct usb_serial *serial) ...@@ -749,6 +737,16 @@ int usb_wwan_resume(struct usb_serial *serial)
if (!portdata || !portdata->opened) if (!portdata || !portdata->opened)
continue; 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++) { for (j = 0; j < N_IN_URB; j++) {
urb = portdata->in_urbs[j]; urb = portdata->in_urbs[j];
err = usb_submit_urb(urb, GFP_ATOMIC); err = usb_submit_urb(urb, GFP_ATOMIC);
......
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