[PATCH v6 2/3] usb: gadget: gadgetfs: prevent ep0 event counter underflow

From: Jing Lin via B4 Relay

Date: Mon Nov 09 2026 - 01:53:10 EST


From: Jing Lin <kayano050408@xxxxxxxxx>

ep0_read() snapshots dev->ev_next, drops dev->lock while copy_to_user()
runs directly from dev->event[], and subtracts the snapshot afterwards.
A concurrent disconnect, connect, setup, or another reader can reset,
deduplicate, or consume the queue in that window. This races on
dev->event[], can drop newly arrived GADGETFS_SETUP events, and wraps
dev->ev_next if the queue shrinks below the snapshot.

Dequeue the events into the local buffer and update dev->ev_next before
dropping dev->lock for copy_to_user().

Fixes: 1da177e4c3f41 ("Linux-2.6.12-rc2")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Jing Lin <kayano050408@xxxxxxxxx>
---
drivers/usb/gadget/legacy/inode.c | 26 ++++++++++----------------
1 file changed, 10 insertions(+), 16 deletions(-)

diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
index 1277982f1..d8dfc1897 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -1227,25 +1227,19 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
break;
}
}
- spin_unlock_irq (&dev->lock);
- len = n * sizeof (struct usb_gadgetfs_event);
- if (copy_to_user (buf, &dev->event, len))
+ len = n * sizeof(struct usb_gadgetfs_event);
+ memcpy(tmp, &dev->event, len);
+ if (dev->ev_next > n) {
+ memmove(&dev->event[0], &dev->event[n],
+ sizeof(struct usb_gadgetfs_event)
+ * (dev->ev_next - n));
+ }
+ dev->ev_next -= n;
+ spin_unlock_irq(&dev->lock);
+ if (copy_to_user(buf, tmp, len))
retval = -EFAULT;
else
retval = len;
- if (len > 0) {
- /* NOTE this doesn't guard against broken drivers;
- * concurrent ep0 readers may lose events.
- */
- spin_lock_irq (&dev->lock);
- if (dev->ev_next > n) {
- memmove(&dev->event[0], &dev->event[n],
- sizeof (struct usb_gadgetfs_event)
- * (dev->ev_next - n));
- }
- dev->ev_next -= n;
- spin_unlock_irq (&dev->lock);
- }
return retval;
}
if (fd->f_flags & O_NONBLOCK) {

--
Git-155)