Commit 19a565d9 authored by Johan Hovold's avatar Johan Hovold

USB: serial: garmin_gps: fix I/O after failed probe and remove

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: 1da177e4 ("Linux-2.6.12-rc2")
Cc: stable <stable@vger.kernel.org>	# 51a2f077 ("USB: introduce usb_anchor")
Reviewed-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarJohan Hovold <johan@kernel.org>
parent 29d15361
...@@ -138,6 +138,7 @@ struct garmin_data { ...@@ -138,6 +138,7 @@ struct garmin_data {
__u8 privpkt[4*6]; __u8 privpkt[4*6];
spinlock_t lock; spinlock_t lock;
struct list_head pktlist; struct list_head pktlist;
struct usb_anchor write_urbs;
}; };
...@@ -905,13 +906,19 @@ static int garmin_init_session(struct usb_serial_port *port) ...@@ -905,13 +906,19 @@ static int garmin_init_session(struct usb_serial_port *port)
sizeof(GARMIN_START_SESSION_REQ), 0); sizeof(GARMIN_START_SESSION_REQ), 0);
if (status < 0) if (status < 0)
break; goto err_kill_urbs;
} }
if (status > 0) if (status > 0)
status = 0; status = 0;
} }
return status;
err_kill_urbs:
usb_kill_anchored_urbs(&garmin_data_p->write_urbs);
usb_kill_urb(port->interrupt_in_urb);
return status; return status;
} }
...@@ -930,7 +937,6 @@ static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port) ...@@ -930,7 +937,6 @@ static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port)
spin_unlock_irqrestore(&garmin_data_p->lock, flags); spin_unlock_irqrestore(&garmin_data_p->lock, flags);
/* shutdown any bulk reads that might be going on */ /* shutdown any bulk reads that might be going on */
usb_kill_urb(port->write_urb);
usb_kill_urb(port->read_urb); usb_kill_urb(port->read_urb);
if (garmin_data_p->state == STATE_RESET) if (garmin_data_p->state == STATE_RESET)
...@@ -953,7 +959,7 @@ static void garmin_close(struct usb_serial_port *port) ...@@ -953,7 +959,7 @@ static void garmin_close(struct usb_serial_port *port)
/* shutdown our urbs */ /* shutdown our urbs */
usb_kill_urb(port->read_urb); 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 */ /* keep reset state so we know that we must start a new session */
if (garmin_data_p->state != STATE_RESET) if (garmin_data_p->state != STATE_RESET)
...@@ -1037,12 +1043,14 @@ static int garmin_write_bulk(struct usb_serial_port *port, ...@@ -1037,12 +1043,14 @@ static int garmin_write_bulk(struct usb_serial_port *port,
} }
/* send it down the pipe */ /* send it down the pipe */
usb_anchor_urb(urb, &garmin_data_p->write_urbs);
status = usb_submit_urb(urb, GFP_ATOMIC); status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) { if (status) {
dev_err(&port->dev, dev_err(&port->dev,
"%s - usb_submit_urb(write bulk) failed with status = %d\n", "%s - usb_submit_urb(write bulk) failed with status = %d\n",
__func__, status); __func__, status);
count = status; count = status;
usb_unanchor_urb(urb);
kfree(buffer); kfree(buffer);
} }
...@@ -1399,6 +1407,7 @@ static int garmin_port_probe(struct usb_serial_port *port) ...@@ -1399,6 +1407,7 @@ static int garmin_port_probe(struct usb_serial_port *port)
garmin_data_p->state = 0; garmin_data_p->state = 0;
garmin_data_p->flags = 0; garmin_data_p->flags = 0;
garmin_data_p->count = 0; garmin_data_p->count = 0;
init_usb_anchor(&garmin_data_p->write_urbs);
usb_set_serial_port_data(port, garmin_data_p); usb_set_serial_port_data(port, garmin_data_p);
status = garmin_init_session(port); status = garmin_init_session(port);
...@@ -1411,6 +1420,7 @@ static int garmin_port_remove(struct usb_serial_port *port) ...@@ -1411,6 +1420,7 @@ static int garmin_port_remove(struct usb_serial_port *port)
{ {
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); 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); usb_kill_urb(port->interrupt_in_urb);
del_timer_sync(&garmin_data_p->timer); del_timer_sync(&garmin_data_p->timer);
kfree(garmin_data_p); kfree(garmin_data_p);
......
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