| From 19a565d9af6e0d828bd0d521d3bafd5017f4ce52 Mon Sep 17 00:00:00 2001 |
| From: Johan Hovold <johan@kernel.org> |
| Date: Wed, 11 Oct 2017 14:02:57 +0200 |
| Subject: USB: serial: garmin_gps: fix I/O after failed probe and remove |
| |
| From: Johan Hovold <johan@kernel.org> |
| |
| commit 19a565d9af6e0d828bd0d521d3bafd5017f4ce52 upstream. |
| |
| Make sure to stop any submitted interrupt and bulk-out URBs before |
| returning after failed probe and when the port is being unbound to avoid |
| later NULL-pointer dereferences in the completion callbacks. |
| |
| Also fix up the related and broken I/O cancellation on failed open and |
| on close. (Note that port->write_urb was never submitted.) |
| |
| Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") |
| Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Signed-off-by: Johan Hovold <johan@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/usb/serial/garmin_gps.c | 16 +++++++++++++--- |
| 1 file changed, 13 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/usb/serial/garmin_gps.c |
| +++ b/drivers/usb/serial/garmin_gps.c |
| @@ -138,6 +138,7 @@ struct garmin_data { |
| __u8 privpkt[4*6]; |
| spinlock_t lock; |
| struct list_head pktlist; |
| + struct usb_anchor write_urbs; |
| }; |
| |
| |
| @@ -905,7 +906,7 @@ static int garmin_init_session(struct us |
| sizeof(GARMIN_START_SESSION_REQ), 0); |
| |
| if (status < 0) |
| - break; |
| + goto err_kill_urbs; |
| } |
| |
| if (status > 0) |
| @@ -913,6 +914,12 @@ static int garmin_init_session(struct us |
| } |
| |
| return status; |
| + |
| +err_kill_urbs: |
| + usb_kill_anchored_urbs(&garmin_data_p->write_urbs); |
| + usb_kill_urb(port->interrupt_in_urb); |
| + |
| + return status; |
| } |
| |
| |
| @@ -930,7 +937,6 @@ static int garmin_open(struct tty_struct |
| spin_unlock_irqrestore(&garmin_data_p->lock, flags); |
| |
| /* shutdown any bulk reads that might be going on */ |
| - usb_kill_urb(port->write_urb); |
| usb_kill_urb(port->read_urb); |
| |
| if (garmin_data_p->state == STATE_RESET) |
| @@ -953,7 +959,7 @@ static void garmin_close(struct usb_seri |
| |
| /* shutdown our urbs */ |
| usb_kill_urb(port->read_urb); |
| - usb_kill_urb(port->write_urb); |
| + usb_kill_anchored_urbs(&garmin_data_p->write_urbs); |
| |
| /* keep reset state so we know that we must start a new session */ |
| if (garmin_data_p->state != STATE_RESET) |
| @@ -1037,12 +1043,14 @@ static int garmin_write_bulk(struct usb_ |
| } |
| |
| /* send it down the pipe */ |
| + usb_anchor_urb(urb, &garmin_data_p->write_urbs); |
| status = usb_submit_urb(urb, GFP_ATOMIC); |
| if (status) { |
| dev_err(&port->dev, |
| "%s - usb_submit_urb(write bulk) failed with status = %d\n", |
| __func__, status); |
| count = status; |
| + usb_unanchor_urb(urb); |
| kfree(buffer); |
| } |
| |
| @@ -1401,6 +1409,7 @@ static int garmin_port_probe(struct usb_ |
| garmin_data_p->state = 0; |
| garmin_data_p->flags = 0; |
| garmin_data_p->count = 0; |
| + init_usb_anchor(&garmin_data_p->write_urbs); |
| usb_set_serial_port_data(port, garmin_data_p); |
| |
| status = garmin_init_session(port); |
| @@ -1413,6 +1422,7 @@ static int garmin_port_remove(struct usb |
| { |
| struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); |
| |
| + usb_kill_anchored_urbs(&garmin_data_p->write_urbs); |
| usb_kill_urb(port->interrupt_in_urb); |
| del_timer_sync(&garmin_data_p->timer); |
| kfree(garmin_data_p); |