From: Sasha Levin Date: Tue, 14 May 2019 18:25:04 +0000 (-0400) Subject: fixes for 4.4 X-Git-Tag: v3.18.140~25 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=fccd60acf91e11acfd631c4b2a89045eced74f18;p=thirdparty%2Fkernel%2Fstable-queue.git fixes for 4.4 Signed-off-by: Sasha Levin --- diff --git a/queue-4.4/series b/queue-4.4/series index 673a40ac667..c6ffa92f01e 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -251,3 +251,5 @@ x86-mds-add-mdsum-variant-to-the-mds-documentation.patch documentation-correct-the-possible-mds-sysfs-values.patch x86-speculation-mds-fix-documentation-typo.patch x86-bugs-change-l1tf-mitigation-string-to-match-upstream.patch +usb-serial-use-variable-for-status.patch +usb-serial-fix-unthrottle-races.patch diff --git a/queue-4.4/usb-serial-fix-unthrottle-races.patch b/queue-4.4/usb-serial-fix-unthrottle-races.patch new file mode 100644 index 00000000000..2dbb697cfd0 --- /dev/null +++ b/queue-4.4/usb-serial-fix-unthrottle-races.patch @@ -0,0 +1,134 @@ +From 3145a3b7ef56fd6d99db804d56afa945e24d7ede 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 + +[ Upstream commit 3f5edd58d040bfa4b74fb89bc02f0bc6b9cd06ab ] + +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: Sasha Levin +--- + drivers/usb/serial/generic.c | 39 +++++++++++++++++++++++++++++------- + 1 file changed, 32 insertions(+), 7 deletions(-) + +diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c +index 101051dce60c7..faead4f32b1ca 100644 +--- a/drivers/usb/serial/generic.c ++++ b/drivers/usb/serial/generic.c +@@ -350,6 +350,7 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb) + 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_callback(struct urb *urb) + 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(struct tty_struct *tty) + 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.20.1 + diff --git a/queue-4.4/usb-serial-use-variable-for-status.patch b/queue-4.4/usb-serial-use-variable-for-status.patch new file mode 100644 index 00000000000..90f715c9256 --- /dev/null +++ b/queue-4.4/usb-serial-use-variable-for-status.patch @@ -0,0 +1,95 @@ +From 6f4e39ecaad2fc7777243da5b4c95dfd2e2dea66 Mon Sep 17 00:00:00 2001 +From: Oliver Neukum +Date: Thu, 14 Jul 2016 15:01:40 +0200 +Subject: USB: serial: use variable for status + +[ Upstream commit 3161da970d38cd6ed2ba8cadec93874d1d06e11e ] + +This patch turns status in a variable read once from the URB. +The long term plan is to deliver status to the callback. +In addition it makes the code a bit more elegant. + +Signed-off-by: Oliver Neukum +Signed-off-by: Johan Hovold +Signed-off-by: Sasha Levin +--- + drivers/usb/serial/generic.c | 18 ++++++++++-------- + 1 file changed, 10 insertions(+), 8 deletions(-) + +diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c +index 54e170dd3dad0..101051dce60c7 100644 +--- a/drivers/usb/serial/generic.c ++++ b/drivers/usb/serial/generic.c +@@ -350,6 +350,7 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb) + struct usb_serial_port *port = urb->context; + unsigned char *data = urb->transfer_buffer; + unsigned long flags; ++ int status = urb->status; + int i; + + for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { +@@ -360,22 +361,22 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb) + + dev_dbg(&port->dev, "%s - urb %d, len %d\n", __func__, i, + urb->actual_length); +- switch (urb->status) { ++ switch (status) { + case 0: + break; + case -ENOENT: + case -ECONNRESET: + case -ESHUTDOWN: + dev_dbg(&port->dev, "%s - urb stopped: %d\n", +- __func__, urb->status); ++ __func__, status); + return; + case -EPIPE: + dev_err(&port->dev, "%s - urb stopped: %d\n", +- __func__, urb->status); ++ __func__, status); + return; + default: + dev_dbg(&port->dev, "%s - nonzero urb status: %d\n", +- __func__, urb->status); ++ __func__, status); + goto resubmit; + } + +@@ -399,6 +400,7 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb) + { + unsigned long flags; + struct usb_serial_port *port = urb->context; ++ int status = urb->status; + int i; + + for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) { +@@ -410,22 +412,22 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb) + set_bit(i, &port->write_urbs_free); + spin_unlock_irqrestore(&port->lock, flags); + +- switch (urb->status) { ++ switch (status) { + case 0: + break; + case -ENOENT: + case -ECONNRESET: + case -ESHUTDOWN: + dev_dbg(&port->dev, "%s - urb stopped: %d\n", +- __func__, urb->status); ++ __func__, status); + return; + case -EPIPE: + dev_err_console(port, "%s - urb stopped: %d\n", +- __func__, urb->status); ++ __func__, status); + return; + default: + dev_err_console(port, "%s - nonzero urb status: %d\n", +- __func__, urb->status); ++ __func__, status); + goto resubmit; + } + +-- +2.20.1 +