diff mbox series

[v2,2/2] USB: serial: opticon: stop all I/O on close()

Message ID 20200114110146.5929-2-johan@kernel.org (mailing list archive)
State Mainlined
Commit e6421583953fd92eba1785f90b228d70345125d6
Headers show
Series [v2,1/2] USB: serial: opticon: add chars_in_buffer() implementation | expand

Commit Message

Johan Hovold Jan. 14, 2020, 11:01 a.m. UTC
Make sure to stop any submitted write URBs on close(). This specifically
avoids a NULL-pointer dereference or use-after-free in case of a late
completion event after driver unbind.

Fixes: 648d4e16567e ("USB: serial: opticon: add write support")
Cc: stable <stable@vger.kernel.org>	# 2.6.30: xxx: USB: serial: opticon: add chars_in_buffer() implementation
Signed-off-by: Johan Hovold <johan@kernel.org>
---

v2
 - add missing address-of operator that was never commit before
   generating the patch


 drivers/usb/serial/opticon.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

Comments

Greg KH Jan. 14, 2020, 12:18 p.m. UTC | #1
On Tue, Jan 14, 2020 at 12:01:46PM +0100, Johan Hovold wrote:
> Make sure to stop any submitted write URBs on close(). This specifically
> avoids a NULL-pointer dereference or use-after-free in case of a late
> completion event after driver unbind.
> 
> Fixes: 648d4e16567e ("USB: serial: opticon: add write support")
> Cc: stable <stable@vger.kernel.org>	# 2.6.30: xxx: USB: serial: opticon: add chars_in_buffer() implementation
> Signed-off-by: Johan Hovold <johan@kernel.org>

Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Johan Hovold Jan. 16, 2020, 4:21 p.m. UTC | #2
On Tue, Jan 14, 2020 at 01:18:57PM +0100, Greg Kroah-Hartman wrote:
> On Tue, Jan 14, 2020 at 12:01:46PM +0100, Johan Hovold wrote:
> > Make sure to stop any submitted write URBs on close(). This specifically
> > avoids a NULL-pointer dereference or use-after-free in case of a late
> > completion event after driver unbind.
> > 
> > Fixes: 648d4e16567e ("USB: serial: opticon: add write support")
> > Cc: stable <stable@vger.kernel.org>	# 2.6.30: xxx: USB: serial: opticon: add chars_in_buffer() implementation
> > Signed-off-by: Johan Hovold <johan@kernel.org>
> 
> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Thanks for the review.

I just submitted a patch preventing individual ports from being unbound,
which almost no USB-serial driver can handle generally without crashing.

And as USB core handles the case were the USB interface driver is
unbound, this one doesn't fix anything critical.

So I'll apply this for -next with the following updated commit message:

    USB: serial: opticon: stop all I/O on close()
    
    Make sure to stop any submitted write URBs on close().
    
    Note that the tty layer will wait up to 30 seconds for the buffers to
    drain before close() is called.

and drop the Fixes and stable tags instead.

Johan
diff mbox series

Patch

diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
index f7bccf14a71f..0af76800bd78 100644
--- a/drivers/usb/serial/opticon.c
+++ b/drivers/usb/serial/opticon.c
@@ -42,6 +42,8 @@  struct opticon_private {
 	bool cts;
 	int outstanding_urbs;
 	int outstanding_bytes;
+
+	struct usb_anchor anchor;
 };
 
 
@@ -150,6 +152,15 @@  static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port)
 	return res;
 }
 
+static void opticon_close(struct usb_serial_port *port)
+{
+	struct opticon_private *priv = usb_get_serial_port_data(port);
+
+	usb_kill_anchored_urbs(&priv->anchor);
+
+	usb_serial_generic_close(port);
+}
+
 static void opticon_write_control_callback(struct urb *urb)
 {
 	struct usb_serial_port *port = urb->context;
@@ -226,10 +237,13 @@  static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port,
 		(unsigned char *)dr, buffer, count,
 		opticon_write_control_callback, port);
 
+	usb_anchor_urb(urb, &priv->anchor);
+
 	/* send it down the pipe */
 	ret = usb_submit_urb(urb, GFP_ATOMIC);
 	if (ret) {
 		dev_err(&port->dev, "failed to submit write urb: %d\n", ret);
+		usb_unanchor_urb(urb);
 		goto error;
 	}
 
@@ -364,6 +378,7 @@  static int opticon_port_probe(struct usb_serial_port *port)
 		return -ENOMEM;
 
 	spin_lock_init(&priv->lock);
+	init_usb_anchor(&priv->anchor);
 
 	usb_set_serial_port_data(port, priv);
 
@@ -391,6 +406,7 @@  static struct usb_serial_driver opticon_device = {
 	.port_probe =		opticon_port_probe,
 	.port_remove =		opticon_port_remove,
 	.open =			opticon_open,
+	.close =		opticon_close,
 	.write =		opticon_write,
 	.write_room = 		opticon_write_room,
 	.chars_in_buffer =	opticon_chars_in_buffer,