Skip to contentSkip to conversation

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

PATCH In review Johan Hovold 3 participants 5 messages Oct 11, 2017 1 message not in the archive

Subsystems (3)
lore
Share & tools
lore

A message that is not in the archive (sent off-list or not yet received): [email protected]

Johan Hovold

author maintainer
#1 lore raw

PATCH 1/5 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 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc stable <[email protected]> # 51a2f077 ("USB: introduce usb_anchor")
---
 drivers/usb/serial/garmin_gps.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)
drivers/usb/serial/garmin_gps.c +13 -3
index 1f439b6e7e6f..8967de6623c4 100644
@@ -138,6 +138,7 @@ struct garmin_data {
 	__u8   privpkt[4*6];
 	spinlock_t lock;
 	struct list_head pktlist;
+	struct usb_anchor write_urbs;
 };
 
 
@@ -905,13 +906,19 @@ static int garmin_init_session(struct usb_serial_port *port)
 					sizeof(GARMIN_START_SESSION_REQ), 0);
 
 			if (status < 0)
-				break;
+				goto err_kill_urbs;
 		}
 
 		if (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;
 }
 
@@ -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);
 
 	/* 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_serial_port *port)
 
 	/* 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_serial_port *port,
 	}
 
 	/* 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);
 	}
 
@@ -1399,6 +1407,7 @@ static int garmin_port_probe(struct usb_serial_port *port)
 	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);
@@ -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);
 
+	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);
Signature · 1 line
2.14.2
Reviewed-by Greg Kroah-Hartman on v1 1/5
#2 lore raw
Quoted 10 lines · Johan Hovold

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")
Cc stable <[email protected]> # 51a2f077 ("USB: introduce usb_anchor")
author maintainer
#3 lore raw
Quoted 5 lines · Greg Kroah-Hartman
Quoted 4 lines · Johan Hovold

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.

Quoted 8 lines
Quoted 6 lines

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")
Cc stable <[email protected]> # 51a2f077 ("USB: introduce usb_anchor")

Thanks for reviewing these. All now applied.

Johan

author maintainer
#4 lore raw

PATCH 2/5 USB: serial: garmin_gps: fix memory leak on probe errors

In reply to a message not in the archive

Make sure to free the port private data before returning after a failed probe attempt.

Fixes 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc stable <[email protected]>
---
 drivers/usb/serial/garmin_gps.c | 6 ++++++
 1 file changed, 6 insertions(+)
drivers/usb/serial/garmin_gps.c +6 -0
index 8967de6623c4..677558c99a97 100644
@@ -1411,6 +1411,12 @@ static int garmin_port_probe(struct usb_serial_port *port)
 	usb_set_serial_port_data(port, garmin_data_p);
 
 	status = garmin_init_session(port);
+	if (status)
+		goto err_free;
+
+	return 0;
+err_free:
+	kfree(garmin_data_p);
 
 	return status;
 }
Signature · 1 line
2.14.2