summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohan Hovold <johan@kernel.org>2019-10-22 16:32:02 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-11-06 13:06:16 +0100
commit3f1a7d903b8d33afb512c457448fa57c90551132 (patch)
tree5bcf279f9a21216f3c7a443f2b32c72e88cd51c8
parentf1b94b60bb1c8aa0ca6db50a8fa44aca65c0f897 (diff)
downloadlinux-3f1a7d903b8d33afb512c457448fa57c90551132.tar.gz
linux-3f1a7d903b8d33afb512c457448fa57c90551132.tar.bz2
linux-3f1a7d903b8d33afb512c457448fa57c90551132.zip
USB: ldusb: fix ring-buffer locking
commit d98ee2a19c3334e9343df3ce254b496f1fc428eb upstream. The custom ring-buffer implementation was merged without any locking or explicit memory barriers, but a spinlock was later added by commit 9d33efd9a791 ("USB: ldusb bugfix"). The lock did not cover the update of the tail index once the entry had been processed, something which could lead to memory corruption on weakly ordered architectures or due to compiler optimisations. Specifically, a completion handler running on another CPU might observe the incremented tail index and update the entry before ld_usb_read() is done with it. Fixes: 2824bd250f0b ("[PATCH] USB: add ldusb driver") Fixes: 9d33efd9a791 ("USB: ldusb bugfix") Cc: stable <stable@vger.kernel.org> # 2.6.13 Signed-off-by: Johan Hovold <johan@kernel.org> Link: https://lore.kernel.org/r/20191022143203.5260-2-johan@kernel.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/misc/ldusb.c4
1 files changed, 2 insertions, 2 deletions
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 6b3a6fd7d271..80c82f9667a1 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -495,11 +495,11 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
retval = -EFAULT;
goto unlock_exit;
}
- dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size;
-
retval = bytes_to_read;
spin_lock_irq(&dev->rbsl);
+ dev->ring_tail = (dev->ring_tail + 1) % ring_buffer_size;
+
if (dev->buffer_overflow) {
dev->buffer_overflow = 0;
spin_unlock_irq(&dev->rbsl);