USB: serial: cyberjack: fix write-URB completion race
authorJohan Hovold <johan@kernel.org>
Mon, 26 Oct 2020 08:25:48 +0000 (09:25 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 10 Nov 2020 09:29:06 +0000 (10:29 +0100)
commit 985616f0457d9f555fff417d0da56174f70cc14f upstream.

The write-URB busy flag was being cleared before the completion handler
was done with the URB, something which could lead to corrupt transfers
due to a racing write request if the URB is resubmitted.

Fixes: 507ca9bc0476 ("[PATCH] USB: add ability for usb-serial drivers to determine if their write urb is currently being used.")
Cc: stable <stable@vger.kernel.org> # 2.6.13
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/cyberjack.c

index 47fbd9f0c0c7a8508f23b562f4a220dbd19bc33f..62821f7a8a23eff5221c5f7b602a5d1e27779303 100644 (file)
@@ -358,11 +358,12 @@ static void cyberjack_write_bulk_callback(struct urb *urb)
        struct cyberjack_private *priv = usb_get_serial_port_data(port);
        struct device *dev = &port->dev;
        int status = urb->status;
+       bool resubmitted = false;
 
-       set_bit(0, &port->write_urbs_free);
        if (status) {
                dev_dbg(dev, "%s - nonzero write bulk status received: %d\n",
                        __func__, status);
+               set_bit(0, &port->write_urbs_free);
                return;
        }
 
@@ -395,6 +396,8 @@ static void cyberjack_write_bulk_callback(struct urb *urb)
                        goto exit;
                }
 
+               resubmitted = true;
+
                dev_dbg(dev, "%s - priv->wrsent=%d\n", __func__, priv->wrsent);
                dev_dbg(dev, "%s - priv->wrfilled=%d\n", __func__, priv->wrfilled);
 
@@ -411,6 +414,8 @@ static void cyberjack_write_bulk_callback(struct urb *urb)
 
 exit:
        spin_unlock(&priv->lock);
+       if (!resubmitted)
+               set_bit(0, &port->write_urbs_free);
        usb_serial_port_softint(port);
 }