From aacec59eafe6c34d81fe8476b4962686ca50d365 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 13 May 2019 13:36:19 +0200 Subject: [PATCH] 5.0-stable patches added patches: usb-serial-fix-unthrottle-races.patch --- queue-5.0/series | 1 + .../usb-serial-fix-unthrottle-races.patch | 132 ++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 queue-5.0/usb-serial-fix-unthrottle-races.patch diff --git a/queue-5.0/series b/queue-5.0/series index 320c05afd48..771ff7c0c7c 100644 --- a/queue-5.0/series +++ b/queue-5.0/series @@ -7,3 +7,4 @@ hwmon-occ-fix-extended-status-bits.patch selftests-seccomp-handle-namespace-failures-gracefully.patch kernfs-fix-barrier-usage-in-__kernfs_new_node.patch virt-vbox-sanity-check-parameter-types-for-hgcm-calls-coming-from-userspace.patch +usb-serial-fix-unthrottle-races.patch diff --git a/queue-5.0/usb-serial-fix-unthrottle-races.patch b/queue-5.0/usb-serial-fix-unthrottle-races.patch new file mode 100644 index 00000000000..7c7d0845679 --- /dev/null +++ b/queue-5.0/usb-serial-fix-unthrottle-races.patch @@ -0,0 +1,132 @@ +From 3f5edd58d040bfa4b74fb89bc02f0bc6b9cd06ab Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Thu, 25 Apr 2019 18:05:36 +0200 +Subject: USB: serial: fix unthrottle races + +From: Johan Hovold + +commit 3f5edd58d040bfa4b74fb89bc02f0bc6b9cd06ab upstream. + +Fix two long-standing bugs which could potentially lead to memory +corruption or leave the port throttled until it is reopened (on weakly +ordered systems), respectively, when read-URB completion races with +unthrottle(). + +First, the URB must not be marked as free before processing is complete +to prevent it from being submitted by unthrottle() on another CPU. + + CPU 1 CPU 2 + ================ ================ + complete() unthrottle() + process_urb(); + smp_mb__before_atomic(); + set_bit(i, free); if (test_and_clear_bit(i, free)) + submit_urb(); + +Second, the URB must be marked as free before checking the throttled +flag to prevent unthrottle() on another CPU from failing to observe that +the URB needs to be submitted if complete() sees that the throttled flag +is set. + + CPU 1 CPU 2 + ================ ================ + complete() unthrottle() + set_bit(i, free); throttled = 0; + smp_mb__after_atomic(); smp_mb(); + if (throttled) if (test_and_clear_bit(i, free)) + return; submit_urb(); + +Note that test_and_clear_bit() only implies barriers when the test is +successful. To handle the case where the URB is still in use an explicit +barrier needs to be added to unthrottle() for the second race condition. + +Fixes: d83b405383c9 ("USB: serial: add support for multiple read urbs") +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/serial/generic.c | 39 ++++++++++++++++++++++++++++++++------- + 1 file changed, 32 insertions(+), 7 deletions(-) + +--- a/drivers/usb/serial/generic.c ++++ b/drivers/usb/serial/generic.c +@@ -376,6 +376,7 @@ void usb_serial_generic_read_bulk_callba + struct usb_serial_port *port = urb->context; + unsigned char *data = urb->transfer_buffer; + unsigned long flags; ++ bool stopped = false; + int status = urb->status; + int i; + +@@ -383,33 +384,51 @@ void usb_serial_generic_read_bulk_callba + if (urb == port->read_urbs[i]) + break; + } +- set_bit(i, &port->read_urbs_free); + + dev_dbg(&port->dev, "%s - urb %d, len %d\n", __func__, i, + urb->actual_length); + switch (status) { + case 0: ++ usb_serial_debug_data(&port->dev, __func__, urb->actual_length, ++ data); ++ port->serial->type->process_read_urb(urb); + break; + case -ENOENT: + case -ECONNRESET: + case -ESHUTDOWN: + dev_dbg(&port->dev, "%s - urb stopped: %d\n", + __func__, status); +- return; ++ stopped = true; ++ break; + case -EPIPE: + dev_err(&port->dev, "%s - urb stopped: %d\n", + __func__, status); +- return; ++ stopped = true; ++ break; + default: + dev_dbg(&port->dev, "%s - nonzero urb status: %d\n", + __func__, status); +- goto resubmit; ++ break; + } + +- usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); +- port->serial->type->process_read_urb(urb); ++ /* ++ * Make sure URB processing is done before marking as free to avoid ++ * racing with unthrottle() on another CPU. Matches the barriers ++ * implied by the test_and_clear_bit() in ++ * usb_serial_generic_submit_read_urb(). ++ */ ++ smp_mb__before_atomic(); ++ set_bit(i, &port->read_urbs_free); ++ /* ++ * Make sure URB is marked as free before checking the throttled flag ++ * to avoid racing with unthrottle() on another CPU. Matches the ++ * smp_mb() in unthrottle(). ++ */ ++ smp_mb__after_atomic(); ++ ++ if (stopped) ++ return; + +-resubmit: + /* Throttle the device if requested by tty */ + spin_lock_irqsave(&port->lock, flags); + port->throttled = port->throttle_req; +@@ -484,6 +503,12 @@ void usb_serial_generic_unthrottle(struc + port->throttled = port->throttle_req = 0; + spin_unlock_irq(&port->lock); + ++ /* ++ * Matches the smp_mb__after_atomic() in ++ * usb_serial_generic_read_bulk_callback(). ++ */ ++ smp_mb(); ++ + if (was_throttled) + usb_serial_generic_submit_read_urbs(port, GFP_KERNEL); + } -- 2.47.2