From: Greg Kroah-Hartman Date: Mon, 13 May 2019 11:24:43 +0000 (+0200) Subject: 4.9-stable patches X-Git-Tag: v5.1.2~33 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=18b24b74e2368c46cc287e684140a52b0768e12a;p=thirdparty%2Fkernel%2Fstable-queue.git 4.9-stable patches added patches: usb-serial-fix-unthrottle-races.patch --- diff --git a/queue-4.9/series b/queue-4.9/series index d50e07ac4b1..eebc79aaf92 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -2,3 +2,4 @@ netfilter-compat-initialize-all-fields-in-xt_init.patch bpf-fix-struct-htab_elem-layout.patch bpf-convert-htab-map-to-hlist_nulls.patch platform-x86-sony-laptop-fix-unintentional-fall-through.patch +usb-serial-fix-unthrottle-races.patch diff --git a/queue-4.9/usb-serial-fix-unthrottle-races.patch b/queue-4.9/usb-serial-fix-unthrottle-races.patch new file mode 100644 index 00000000000..26853a15e8e --- /dev/null +++ b/queue-4.9/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 +@@ -350,6 +350,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; + +@@ -357,33 +358,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; +@@ -458,6 +477,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); + }