All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/2] USB: ldusb: fix ring-buffer bugs
@ 2019-10-18 15:19 Johan Hovold
  2019-10-18 15:19 ` [PATCH v2 1/2] USB: ldusb: fix read info leaks Johan Hovold
  2019-10-18 15:19 ` [PATCH RFC v2 2/2] USB: ldusb: fix ring-buffer locking Johan Hovold
  0 siblings, 2 replies; 8+ messages in thread
From: Johan Hovold @ 2019-10-18 15:19 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Alan Stern, Oliver Neukum, Paul E . McKenney, linux-usb,
	linux-kernel, Johan Hovold

Syzbot has been reporting a slab-out-of-bounds/bad user copy in ldusb
for some time now.

This turned out to due to a bug in the read() implementation, which
would have read() access the uninitialised ring buffer and leak huge
amounts of slab data on URB completion errors (e.g. disconnect).

The first patch plugs the info leaks.

The second patch fixes a couple of issues in the custom ring-buffer
implementation, which before the first patch also could have led to
info leaks.

In an attempt to avoid copying the ring-buffer entry to a temporary
buffer while holding the spinlock, I added an smp_rmb() before
copy_to_user() which I think will suffice, but I'd appreciate if you
could help me verify that. Hence the RFC on that one.

The first commit could go to Linus meanwhile.

Johan

v2
 - fix buffer-entry length check in 1/2


Johan Hovold (2):
  USB: ldusb: fix read info leaks
  USB: ldusb: fix ring-buffer locking

 drivers/usb/misc/ldusb.c | 31 ++++++++++++++++++++++---------
 1 file changed, 22 insertions(+), 9 deletions(-)

-- 
2.23.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 1/2] USB: ldusb: fix read info leaks
  2019-10-18 15:19 [PATCH v2 0/2] USB: ldusb: fix ring-buffer bugs Johan Hovold
@ 2019-10-18 15:19 ` Johan Hovold
  2019-10-18 15:19 ` [PATCH RFC v2 2/2] USB: ldusb: fix ring-buffer locking Johan Hovold
  1 sibling, 0 replies; 8+ messages in thread
From: Johan Hovold @ 2019-10-18 15:19 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Alan Stern, Oliver Neukum, Paul E . McKenney, linux-usb,
	linux-kernel, Johan Hovold, stable, syzbot+6fe95b826644f7f12b0b

Fix broken read implementation, which could be used to trigger slab info
leaks.

The driver failed to check if the custom ring buffer was still empty
when waking up after having waited for more data. This would happen on
every interrupt-in completion, even if no data had been added to the
ring buffer (e.g. on disconnect events).

Due to missing sanity checks and uninitialised (kmalloced) ring-buffer
entries, this meant that huge slab info leaks could easily be triggered.

Note that the empty-buffer check after wakeup is enough to fix the info
leak on disconnect, but let's clear the buffer on allocation and add a
sanity check to read() to prevent further leaks.

Fixes: 2824bd250f0b ("[PATCH] USB: add ldusb driver")
Cc: stable <stable@vger.kernel.org>     # 2.6.13
Reported-by: syzbot+6fe95b826644f7f12b0b@syzkaller.appspotmail.com
Signed-off-by: Johan Hovold <johan@kernel.org>
---
 drivers/usb/misc/ldusb.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 147c90c2a4e5..15b5f06fb0b3 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -464,7 +464,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
 
 	/* wait for data */
 	spin_lock_irq(&dev->rbsl);
-	if (dev->ring_head == dev->ring_tail) {
+	while (dev->ring_head == dev->ring_tail) {
 		dev->interrupt_in_done = 0;
 		spin_unlock_irq(&dev->rbsl);
 		if (file->f_flags & O_NONBLOCK) {
@@ -474,12 +474,17 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
 		retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done);
 		if (retval < 0)
 			goto unlock_exit;
-	} else {
-		spin_unlock_irq(&dev->rbsl);
+
+		spin_lock_irq(&dev->rbsl);
 	}
+	spin_unlock_irq(&dev->rbsl);
 
 	/* actual_buffer contains actual_length + interrupt_in_buffer */
 	actual_buffer = (size_t *)(dev->ring_buffer + dev->ring_tail * (sizeof(size_t)+dev->interrupt_in_endpoint_size));
+	if (*actual_buffer > dev->interrupt_in_endpoint_size) {
+		retval = -EIO;
+		goto unlock_exit;
+	}
 	bytes_to_read = min(count, *actual_buffer);
 	if (bytes_to_read < *actual_buffer)
 		dev_warn(&dev->intf->dev, "Read buffer overflow, %zd bytes dropped\n",
@@ -690,10 +695,9 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
 		dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n");
 
 	dev->interrupt_in_endpoint_size = usb_endpoint_maxp(dev->interrupt_in_endpoint);
-	dev->ring_buffer =
-		kmalloc_array(ring_buffer_size,
-			      sizeof(size_t) + dev->interrupt_in_endpoint_size,
-			      GFP_KERNEL);
+	dev->ring_buffer = kcalloc(ring_buffer_size,
+			sizeof(size_t) + dev->interrupt_in_endpoint_size,
+			GFP_KERNEL);
 	if (!dev->ring_buffer)
 		goto error;
 	dev->interrupt_in_buffer = kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL);
-- 
2.23.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH RFC v2 2/2] USB: ldusb: fix ring-buffer locking
  2019-10-18 15:19 [PATCH v2 0/2] USB: ldusb: fix ring-buffer bugs Johan Hovold
  2019-10-18 15:19 ` [PATCH v2 1/2] USB: ldusb: fix read info leaks Johan Hovold
@ 2019-10-18 15:19 ` Johan Hovold
  2019-10-18 18:54   ` Greg Kroah-Hartman
  2019-10-21 15:17   ` Alan Stern
  1 sibling, 2 replies; 8+ messages in thread
From: Johan Hovold @ 2019-10-18 15:19 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Alan Stern, Oliver Neukum, Paul E . McKenney, linux-usb,
	linux-kernel, Johan Hovold, stable

The custom ring-buffer implementation was merged without any locking
whatsoever, but a spinlock was later added by commit 9d33efd9a791
("USB: ldusb bugfix").

The lock did not cover the loads from the ring-buffer entry after
determining the buffer was non-empty, nor the update of the tail index
once the entry had been processed. The former could lead to stale data
being returned, while the latter could lead to memory corruption on
sufficiently weakly ordered architectures.

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>
---
 drivers/usb/misc/ldusb.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 15b5f06fb0b3..6b5843b0071e 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -477,11 +477,11 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
 
 		spin_lock_irq(&dev->rbsl);
 	}
-	spin_unlock_irq(&dev->rbsl);
 
 	/* actual_buffer contains actual_length + interrupt_in_buffer */
 	actual_buffer = (size_t *)(dev->ring_buffer + dev->ring_tail * (sizeof(size_t)+dev->interrupt_in_endpoint_size));
 	if (*actual_buffer > dev->interrupt_in_endpoint_size) {
+		spin_unlock_irq(&dev->rbsl);
 		retval = -EIO;
 		goto unlock_exit;
 	}
@@ -489,17 +489,26 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
 	if (bytes_to_read < *actual_buffer)
 		dev_warn(&dev->intf->dev, "Read buffer overflow, %zd bytes dropped\n",
 			 *actual_buffer-bytes_to_read);
+	spin_unlock_irq(&dev->rbsl);
+
+	/*
+	 * Pairs with spin_unlock_irqrestore() in
+	 * ld_usb_interrupt_in_callback() and makes sure the ring-buffer entry
+	 * has been updated before copy_to_user().
+	 */
+	smp_rmb();
 
 	/* copy one interrupt_in_buffer from ring_buffer into userspace */
 	if (copy_to_user(buffer, actual_buffer+1, bytes_to_read)) {
 		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);
-- 
2.23.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH RFC v2 2/2] USB: ldusb: fix ring-buffer locking
  2019-10-18 15:19 ` [PATCH RFC v2 2/2] USB: ldusb: fix ring-buffer locking Johan Hovold
@ 2019-10-18 18:54   ` Greg Kroah-Hartman
  2019-10-21  8:56     ` Johan Hovold
  2019-10-21 15:17   ` Alan Stern
  1 sibling, 1 reply; 8+ messages in thread
From: Greg Kroah-Hartman @ 2019-10-18 18:54 UTC (permalink / raw)
  To: Johan Hovold
  Cc: Alan Stern, Oliver Neukum, Paul E . McKenney, linux-usb,
	linux-kernel, stable

On Fri, Oct 18, 2019 at 05:19:55PM +0200, Johan Hovold wrote:
> The custom ring-buffer implementation was merged without any locking
> whatsoever, but a spinlock was later added by commit 9d33efd9a791
> ("USB: ldusb bugfix").
> 
> The lock did not cover the loads from the ring-buffer entry after
> determining the buffer was non-empty, nor the update of the tail index
> once the entry had been processed. The former could lead to stale data
> being returned, while the latter could lead to memory corruption on
> sufficiently weakly ordered architectures.

Ugh.

This almost looks sane, but what's the odds there is some other issue in
here as well?  Would it make sense to just convert the code to use the
"standard" ring buffer code instead?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH RFC v2 2/2] USB: ldusb: fix ring-buffer locking
  2019-10-18 18:54   ` Greg Kroah-Hartman
@ 2019-10-21  8:56     ` Johan Hovold
  2019-10-21 13:48       ` Greg Kroah-Hartman
  0 siblings, 1 reply; 8+ messages in thread
From: Johan Hovold @ 2019-10-21  8:56 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Johan Hovold, Alan Stern, Oliver Neukum, Paul E . McKenney,
	linux-usb, linux-kernel, stable

On Fri, Oct 18, 2019 at 11:54:58AM -0700, Greg Kroah-Hartman wrote:
> On Fri, Oct 18, 2019 at 05:19:55PM +0200, Johan Hovold wrote:
> > The custom ring-buffer implementation was merged without any locking
> > whatsoever, but a spinlock was later added by commit 9d33efd9a791
> > ("USB: ldusb bugfix").
> > 
> > The lock did not cover the loads from the ring-buffer entry after
> > determining the buffer was non-empty, nor the update of the tail index
> > once the entry had been processed. The former could lead to stale data
> > being returned, while the latter could lead to memory corruption on
> > sufficiently weakly ordered architectures.
> 
> Ugh.
> 
> This almost looks sane, but what's the odds there is some other issue in
> here as well?  Would it make sense to just convert the code to use the
> "standard" ring buffer code instead?

Yeah, long term that may be the right thing to do, but I wanted a
minimal fix addressing the issue at hand without having to reimplement
the driver and fix all other (less-critical) issues in there...

For the ring-buffer corruption / info-leak issue, these two patches
should be sufficient though.

Copying the ring-buffer entry to a temporary buffer while holding the
lock might still be preferred to avoid having to deal with barrier
subtleties. But unless someone speaks out against 2/2, I'd just go ahead
and apply it.

Johan

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH RFC v2 2/2] USB: ldusb: fix ring-buffer locking
  2019-10-21  8:56     ` Johan Hovold
@ 2019-10-21 13:48       ` Greg Kroah-Hartman
  0 siblings, 0 replies; 8+ messages in thread
From: Greg Kroah-Hartman @ 2019-10-21 13:48 UTC (permalink / raw)
  To: Johan Hovold
  Cc: Alan Stern, Oliver Neukum, Paul E . McKenney, linux-usb,
	linux-kernel, stable

On Mon, Oct 21, 2019 at 10:56:27AM +0200, Johan Hovold wrote:
> On Fri, Oct 18, 2019 at 11:54:58AM -0700, Greg Kroah-Hartman wrote:
> > On Fri, Oct 18, 2019 at 05:19:55PM +0200, Johan Hovold wrote:
> > > The custom ring-buffer implementation was merged without any locking
> > > whatsoever, but a spinlock was later added by commit 9d33efd9a791
> > > ("USB: ldusb bugfix").
> > > 
> > > The lock did not cover the loads from the ring-buffer entry after
> > > determining the buffer was non-empty, nor the update of the tail index
> > > once the entry had been processed. The former could lead to stale data
> > > being returned, while the latter could lead to memory corruption on
> > > sufficiently weakly ordered architectures.
> > 
> > Ugh.
> > 
> > This almost looks sane, but what's the odds there is some other issue in
> > here as well?  Would it make sense to just convert the code to use the
> > "standard" ring buffer code instead?
> 
> Yeah, long term that may be the right thing to do, but I wanted a
> minimal fix addressing the issue at hand without having to reimplement
> the driver and fix all other (less-critical) issues in there...
> 
> For the ring-buffer corruption / info-leak issue, these two patches
> should be sufficient though.
> 
> Copying the ring-buffer entry to a temporary buffer while holding the
> lock might still be preferred to avoid having to deal with barrier
> subtleties. But unless someone speaks out against 2/2, I'd just go ahead
> and apply it.

Ok, feel free to resend this and I'll queue it up, it's gone from my
queue :(

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH RFC v2 2/2] USB: ldusb: fix ring-buffer locking
  2019-10-18 15:19 ` [PATCH RFC v2 2/2] USB: ldusb: fix ring-buffer locking Johan Hovold
  2019-10-18 18:54   ` Greg Kroah-Hartman
@ 2019-10-21 15:17   ` Alan Stern
  2019-10-21 18:30     ` Johan Hovold
  1 sibling, 1 reply; 8+ messages in thread
From: Alan Stern @ 2019-10-21 15:17 UTC (permalink / raw)
  To: Johan Hovold
  Cc: Greg Kroah-Hartman, Oliver Neukum, Paul E . McKenney, linux-usb,
	linux-kernel, stable

On Fri, 18 Oct 2019, Johan Hovold wrote:

> The custom ring-buffer implementation was merged without any locking
> whatsoever, but a spinlock was later added by commit 9d33efd9a791
> ("USB: ldusb bugfix").
> 
> The lock did not cover the loads from the ring-buffer entry after
> determining the buffer was non-empty, nor the update of the tail index
> once the entry had been processed. The former could lead to stale data
> being returned, while the latter could lead to memory corruption on
> sufficiently weakly ordered architectures.

Let's see if I understand this correctly.

The completion routine stores a buffer-length value at the location 
actual_buffer points to, and it stores the buffer contents themselves 
in the immediately following bytes.  All this happens while the 
dev->rbsl spinlock is held.

Later on the read routine loads a value from *actual_buffer while
holding the spinlock, but drops the spinlock before copying the
immediately following buffer contents to userspace.

Your question is whether the read routine needs to call smp_rmb() after 
dropping the spinlock and before doing copy_to_user(), right?

The answer is: No, smp_rmb() isn't needed.  All the data stored while
ld_usb_interrupt_in_callback() held the spinlock will be visible to
ld_usb_read() while it holds the spinlock and afterward (assuming the
critical section in ld_usb_read() runs after the critical section in 
ld_usb_interrupt_in_callback() -- but you know this is true because of 
the value you read from *actual_buffer).

Alan Stern

> 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>
> ---
>  drivers/usb/misc/ldusb.c | 15 ++++++++++++---
>  1 file changed, 12 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
> index 15b5f06fb0b3..6b5843b0071e 100644
> --- a/drivers/usb/misc/ldusb.c
> +++ b/drivers/usb/misc/ldusb.c
> @@ -477,11 +477,11 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
>  
>  		spin_lock_irq(&dev->rbsl);
>  	}
> -	spin_unlock_irq(&dev->rbsl);
>  
>  	/* actual_buffer contains actual_length + interrupt_in_buffer */
>  	actual_buffer = (size_t *)(dev->ring_buffer + dev->ring_tail * (sizeof(size_t)+dev->interrupt_in_endpoint_size));
>  	if (*actual_buffer > dev->interrupt_in_endpoint_size) {
> +		spin_unlock_irq(&dev->rbsl);
>  		retval = -EIO;
>  		goto unlock_exit;
>  	}
> @@ -489,17 +489,26 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
>  	if (bytes_to_read < *actual_buffer)
>  		dev_warn(&dev->intf->dev, "Read buffer overflow, %zd bytes dropped\n",
>  			 *actual_buffer-bytes_to_read);
> +	spin_unlock_irq(&dev->rbsl);
> +
> +	/*
> +	 * Pairs with spin_unlock_irqrestore() in
> +	 * ld_usb_interrupt_in_callback() and makes sure the ring-buffer entry
> +	 * has been updated before copy_to_user().
> +	 */
> +	smp_rmb();
>  
>  	/* copy one interrupt_in_buffer from ring_buffer into userspace */
>  	if (copy_to_user(buffer, actual_buffer+1, bytes_to_read)) {
>  		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);
> 



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH RFC v2 2/2] USB: ldusb: fix ring-buffer locking
  2019-10-21 15:17   ` Alan Stern
@ 2019-10-21 18:30     ` Johan Hovold
  0 siblings, 0 replies; 8+ messages in thread
From: Johan Hovold @ 2019-10-21 18:30 UTC (permalink / raw)
  To: Alan Stern
  Cc: Johan Hovold, Greg Kroah-Hartman, Oliver Neukum,
	Paul E . McKenney, linux-usb, linux-kernel, stable

On Mon, Oct 21, 2019 at 11:17:11AM -0400, Alan Stern wrote:
> On Fri, 18 Oct 2019, Johan Hovold wrote:
> 
> > The custom ring-buffer implementation was merged without any locking
> > whatsoever, but a spinlock was later added by commit 9d33efd9a791
> > ("USB: ldusb bugfix").
> > 
> > The lock did not cover the loads from the ring-buffer entry after
> > determining the buffer was non-empty, nor the update of the tail index
> > once the entry had been processed. The former could lead to stale data
> > being returned, while the latter could lead to memory corruption on
> > sufficiently weakly ordered architectures.
> 
> Let's see if I understand this correctly.
> 
> The completion routine stores a buffer-length value at the location 
> actual_buffer points to, and it stores the buffer contents themselves 
> in the immediately following bytes.  All this happens while the 
> dev->rbsl spinlock is held.

Right.

> Later on the read routine loads a value from *actual_buffer while
> holding the spinlock, but drops the spinlock before copying the
> immediately following buffer contents to userspace.

It doesn't currently hold the spinlock while reading *actual_buffer,
only when checking if the ring-buffer is non-empty. The patch below
extends the check to cover also the load from *actual_buffer.

> Your question is whether the read routine needs to call smp_rmb() after 
> dropping the spinlock and before doing copy_to_user(), right?

Right, or alternatively, if an smp_rmb() after dropping the spinlock and
before loading *actual_buffer is needed.

> The answer is: No, smp_rmb() isn't needed.  All the data stored while
> ld_usb_interrupt_in_callback() held the spinlock will be visible to
> ld_usb_read() while it holds the spinlock and afterward (assuming the
> critical section in ld_usb_read() runs after the critical section in 
> ld_usb_interrupt_in_callback() -- but you know this is true because of 
> the value you read from *actual_buffer).

Did you mean the value "read from dev->ring_head" (which tells us the
ring-buffer has been updated) here?

We currently have something like this in ld_usb_read():

	spin_lock_irq(&lock);
	while (head == tail) {
		spin_unlock(&lock);
		wait_event(event);
		spin_lock(&lock);
	}
	spin_unlock_irq(&lock);

	entry = &buffer[tail];
	len = *entry;
	copy_to_user(buf, entry + 1, len);

	/* update tail */

And without an smp_rmb() after dropping the spinlock, what prevents the
load from *entry from being done before the load from head? Nothing,
right (the spin_unlock_irq() is only a compiler barrier for later
loads)? But that's fine because all stores done by the completion
handler under the spinlock would of course be visible at that point.

So the current code is fine wrt to copy_to_user(), and only the tail
bits below are actually needed.

Thanks, Alan! Had myself confused there.

Johan

> > 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>
> > ---
> >  drivers/usb/misc/ldusb.c | 15 ++++++++++++---
> >  1 file changed, 12 insertions(+), 3 deletions(-)
> > 
> > diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
> > index 15b5f06fb0b3..6b5843b0071e 100644
> > --- a/drivers/usb/misc/ldusb.c
> > +++ b/drivers/usb/misc/ldusb.c
> > @@ -477,11 +477,11 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
> >  
> >  		spin_lock_irq(&dev->rbsl);
> >  	}
> > -	spin_unlock_irq(&dev->rbsl);
> >  
> >  	/* actual_buffer contains actual_length + interrupt_in_buffer */
> >  	actual_buffer = (size_t *)(dev->ring_buffer + dev->ring_tail * (sizeof(size_t)+dev->interrupt_in_endpoint_size));
> >  	if (*actual_buffer > dev->interrupt_in_endpoint_size) {
> > +		spin_unlock_irq(&dev->rbsl);
> >  		retval = -EIO;
> >  		goto unlock_exit;
> >  	}
> > @@ -489,17 +489,26 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
> >  	if (bytes_to_read < *actual_buffer)
> >  		dev_warn(&dev->intf->dev, "Read buffer overflow, %zd bytes dropped\n",
> >  			 *actual_buffer-bytes_to_read);
> > +	spin_unlock_irq(&dev->rbsl);
> > +
> > +	/*
> > +	 * Pairs with spin_unlock_irqrestore() in
> > +	 * ld_usb_interrupt_in_callback() and makes sure the ring-buffer entry
> > +	 * has been updated before copy_to_user().
> > +	 */
> > +	smp_rmb();
> >  
> >  	/* copy one interrupt_in_buffer from ring_buffer into userspace */
> >  	if (copy_to_user(buffer, actual_buffer+1, bytes_to_read)) {
> >  		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);
> > 
> 
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2019-10-21 18:30 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-18 15:19 [PATCH v2 0/2] USB: ldusb: fix ring-buffer bugs Johan Hovold
2019-10-18 15:19 ` [PATCH v2 1/2] USB: ldusb: fix read info leaks Johan Hovold
2019-10-18 15:19 ` [PATCH RFC v2 2/2] USB: ldusb: fix ring-buffer locking Johan Hovold
2019-10-18 18:54   ` Greg Kroah-Hartman
2019-10-21  8:56     ` Johan Hovold
2019-10-21 13:48       ` Greg Kroah-Hartman
2019-10-21 15:17   ` Alan Stern
2019-10-21 18:30     ` Johan Hovold

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.