* Forwarded: [PATCH] usb: gadgetfs: fix use-after-free in ep_open()
2026-07-31 1:28 [syzbot] [usb?] KASAN: slab-use-after-free Read in ep_open syzbot
@ 2026-07-31 4:26 ` syzbot
2026-07-31 4:44 ` syzbot
` (3 subsequent siblings)
4 siblings, 0 replies; 15+ messages in thread
From: syzbot @ 2026-07-31 4:26 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH] usb: gadgetfs: fix use-after-free in ep_open()
Author: kartikey406@gmail.com
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-kernelci
ep_open() dereferenced inode->i_private (an ep_data pointer) and
locked its embedded mutex before ever validating that the object was
still alive:
struct ep_data *data = inode->i_private;
if (mutex_lock_interruptible(&data->lock) != 0)
return -EINTR;
spin_lock_irq(&data->dev->lock);
if (data->dev->state == STATE_DEV_UNBOUND)
...
The liveness check (dev->state == STATE_DEV_UNBOUND) only happened
*after* data->lock had already been touched. destroy_ep_files(),
called from gadgetfs_unbind(), can free the same ep_data
concurrently via put_ep(), since nothing prevented an in-flight
open() from racing the teardown. KASAN reports a slab-use-after-free
read inside __mutex_lock_common() from ep_open(), with the object
freed by a concurrent gadgetfs_unbind() -> destroy_ep_files() ->
put_ep() -> kfree() on another task.
This exact race was identified by Al Viro on LKML in 2006 ("races in
drivers/usb/gadget/inode.c"), including the correct fix direction,
but it was never applied to ep_open() itself. Later fixes to this
file (the udc_usage counter, CVE-2022-4382) hardened the I/O paths
and the mount/unmount race, but left this specific ordering bug in
place.
Fix it by reordering ep_open() so that dev->state and inode->i_private
are only read while holding dev->lock -- reached via
inode->i_sb->s_fs_info, which stays valid for the life of the mount,
independent of any individual ep_data -- and by pinning the object
with get_ep() before dev->lock is dropped and before data->lock is
touched. This guarantees put_ep()/kfree() cannot race the mutex lock
in ep_open().
This fix depends on dev->state being set to STATE_DEV_UNBOUND under
dev->lock before any call to destroy_ep_files(), so that ep_open()
seeing a "bound" state is a guarantee that no free is in progress.
gadgetfs_unbind() already does this correctly. activate_ep_files()'s
enomem0 error-cleanup path did not: it called destroy_ep_files()
directly without first setting dev->state, which would have left the
same race open on the bind-failure path. This patch adds the missing
state transition there as well, so the invariant holds for every
caller of destroy_ep_files().
Reported-by: syzbot+df9e891bf8ea586f846b@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=df9e891bf8ea586f846b
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
drivers/usb/gadget/legacy/inode.c | 37 ++++++++++++++++++++++---------
1 file changed, 27 insertions(+), 10 deletions(-)
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
index d87a8ab51510..95e3bcedd33d 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -817,25 +817,39 @@ ep_config (struct ep_data *data, const char *buf, size_t len)
static int
ep_open (struct inode *inode, struct file *fd)
{
- struct ep_data *data = inode->i_private;
- int value = -EBUSY;
+ struct dev_data *dev = inode->i_sb->s_fs_info;
+ struct ep_data *data;
+ int value = -ENODEV;
+
+ spin_lock_irq (&dev->lock);
+ if (dev->state == STATE_DEV_UNBOUND) {
+ spin_unlock_irq (&dev->lock);
+ return -ENOENT;
+ }
+ data = inode->i_private;
+ get_ep (data);
+ spin_unlock_irq (&dev->lock);
- if (mutex_lock_interruptible(&data->lock) != 0)
+ if (mutex_lock_interruptible(&data->lock) != 0) {
+ put_ep (data);
return -EINTR;
- spin_lock_irq (&data->dev->lock);
- if (data->dev->state == STATE_DEV_UNBOUND)
+ }
+
+ value = -EBUSY;
+ spin_lock_irq (&dev->lock);
+ if (dev->state == STATE_DEV_UNBOUND)
value = -ENOENT;
else if (data->state == STATE_EP_DISABLED) {
value = 0;
data->state = STATE_EP_READY;
- get_ep (data);
fd->private_data = data;
- VDEBUG (data->dev, "%s ready\n", data->name);
+ VDEBUG (dev, "%s ready\n", data->name);
} else
- DBG (data->dev, "%s state %d\n",
- data->name, data->state);
- spin_unlock_irq (&data->dev->lock);
+ DBG (dev, "%s state %d\n", data->name, data->state);
+ spin_unlock_irq (&dev->lock);
mutex_unlock(&data->lock);
+ if (value)
+ put_ep (data);
return value;
}
@@ -1632,6 +1646,9 @@ static int activate_ep_files (struct dev_data *dev)
kfree (data);
enomem0:
DBG (dev, "%s enomem\n", __func__);
+ spin_lock_irq (&dev->lock);
+ dev->state = STATE_DEV_UNBOUND;
+ spin_unlock_irq (&dev->lock);
destroy_ep_files (dev);
return -ENOMEM;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* Forwarded: [PATCH] usb: gadgetfs: fix use-after-free in ep_open()
2026-07-31 1:28 [syzbot] [usb?] KASAN: slab-use-after-free Read in ep_open syzbot
2026-07-31 4:26 ` Forwarded: [PATCH] usb: gadgetfs: fix use-after-free in ep_open() syzbot
@ 2026-07-31 4:44 ` syzbot
2026-07-31 8:09 ` syzbot
` (2 subsequent siblings)
4 siblings, 0 replies; 15+ messages in thread
From: syzbot @ 2026-07-31 4:44 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH] usb: gadgetfs: fix use-after-free in ep_open()
Author: kartikey406@gmail.com
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-kernelci
ep_open() dereferenced inode->i_private and locked its embedded
mutex before checking whether the underlying ep_data was still
alive. destroy_ep_files(), called from gadgetfs_unbind(), can free
that same ep_data concurrently, since nothing prevented an in-flight
open() from racing the teardown. KASAN reports a slab-use-after-free
read inside __mutex_lock_common() from ep_open(), with the object
freed by a concurrent gadgetfs_unbind() -> destroy_ep_files() ->
put_ep() -> kfree().
This race was identified by Al Viro on LKML in 2006 ("races in
drivers/usb/gadget/inode.c") but never fixed in ep_open() itself.
Fix it by checking dev->state and reading inode->i_private only
under dev->lock, and pinning the result with get_ep() before
dev->lock is dropped and before data->lock is touched. dev is
reached via the file-scope singleton the_device, which stays valid
for the duration of any open() in progress, so no dereference of
ep_data happens before its liveness is confirmed.
This depends on dev->state being set to STATE_DEV_UNBOUND under
dev->lock before destroy_ep_files() is called. gadgetfs_unbind()
already does this; activate_ep_files()'s enomem0 cleanup path did
not, leaving the same race open on the bind-failure path. This patch
adds the missing state transition there too.
Reported-by: syzbot+df9e891bf8ea586f846b@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=df9e891bf8ea586f846b
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
drivers/usb/gadget/legacy/inode.c | 40 +++++++++++++++++++++----------
1 file changed, 28 insertions(+), 12 deletions(-)
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
index d87a8ab51510..0d0989d79020 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -235,6 +235,7 @@ static void put_ep (struct ep_data *data)
static const char *CHIP;
static DEFINE_MUTEX(sb_mutex); /* Serialize superblock operations */
+static struct dev_data *the_device;
/*----------------------------------------------------------------------*/
@@ -817,25 +818,39 @@ ep_config (struct ep_data *data, const char *buf, size_t len)
static int
ep_open (struct inode *inode, struct file *fd)
{
- struct ep_data *data = inode->i_private;
- int value = -EBUSY;
+ struct dev_data *dev = the_device;
+ struct ep_data *data;
+ int value = -ENODEV;
+
+ spin_lock_irq (&dev->lock);
+ if (dev->state == STATE_DEV_UNBOUND) {
+ spin_unlock_irq (&dev->lock);
+ return -ENOENT;
+ }
+ data = inode->i_private;
+ get_ep (data);
+ spin_unlock_irq (&dev->lock);
- if (mutex_lock_interruptible(&data->lock) != 0)
+ if (mutex_lock_interruptible(&data->lock) != 0) {
+ put_ep (data);
return -EINTR;
- spin_lock_irq (&data->dev->lock);
- if (data->dev->state == STATE_DEV_UNBOUND)
+ }
+
+ value = -EBUSY;
+ spin_lock_irq (&dev->lock);
+ if (dev->state == STATE_DEV_UNBOUND)
value = -ENOENT;
else if (data->state == STATE_EP_DISABLED) {
value = 0;
data->state = STATE_EP_READY;
- get_ep (data);
fd->private_data = data;
- VDEBUG (data->dev, "%s ready\n", data->name);
+ VDEBUG (dev, "%s ready\n", data->name);
} else
- DBG (data->dev, "%s state %d\n",
- data->name, data->state);
- spin_unlock_irq (&data->dev->lock);
+ DBG (dev, "%s state %d\n", data->name, data->state);
+ spin_unlock_irq (&dev->lock);
mutex_unlock(&data->lock);
+ if (value)
+ put_ep (data);
return value;
}
@@ -1632,6 +1647,9 @@ static int activate_ep_files (struct dev_data *dev)
kfree (data);
enomem0:
DBG (dev, "%s enomem\n", __func__);
+ spin_lock_irq (&dev->lock);
+ dev->state = STATE_DEV_UNBOUND;
+ spin_unlock_irq (&dev->lock);
destroy_ep_files (dev);
return -ENOMEM;
}
@@ -1663,8 +1681,6 @@ gadgetfs_unbind (struct usb_gadget *gadget)
put_dev (dev);
}
-static struct dev_data *the_device;
-
static int gadgetfs_bind(struct usb_gadget *gadget,
struct usb_gadget_driver *driver)
{
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* Forwarded: [PATCH] usb: gadgetfs: fix use-after-free in ep_open()
2026-07-31 1:28 [syzbot] [usb?] KASAN: slab-use-after-free Read in ep_open syzbot
2026-07-31 4:26 ` Forwarded: [PATCH] usb: gadgetfs: fix use-after-free in ep_open() syzbot
2026-07-31 4:44 ` syzbot
@ 2026-07-31 8:09 ` syzbot
2026-07-31 11:40 ` Forwarded: [PATCH v2] " syzbot
2026-08-17 13:42 ` [syzbot] [usb?] KASAN: slab-use-after-free Read in ep_open syzbot
4 siblings, 0 replies; 15+ messages in thread
From: syzbot @ 2026-07-31 8:09 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH] usb: gadgetfs: fix use-after-free in ep_open()
Author: kartikey406@gmail.com
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-kernelci
ep_open() dereferenced inode->i_private and locked its embedded
mutex before checking whether the underlying ep_data was still
alive. destroy_ep_files(), called from gadgetfs_unbind(), can free
that same ep_data concurrently, since nothing prevented an in-flight
open() from racing the teardown. KASAN reports a slab-use-after-free
in ep_open(), with the object freed by a concurrent gadgetfs_unbind()
-> destroy_ep_files() -> put_ep() -> kfree().
This race was identified by Al Viro on LKML in 2006 ("races in
drivers/usb/gadget/inode.c"), including the fix direction, but it
was never applied to ep_open() itself.
Fix it as originally suggested: add an inode back-pointer to
ep_data, have destroy_ep_files() clear inode->i_private to NULL
under dev->lock before the object can be freed, and have ep_open()
read inode->i_private and pin the result with get_ep() under that
same lock, bailing out with -ENOENT if it finds NULL. This makes
liveness self-evident at the point of use instead of being inferred
from device state, so it holds regardless of which path frees the
endpoint.
gadgetfs_create_file() gains an optional inode-out parameter so
activate_ep_files() can capture the inode it creates; the ep0 caller
in gadgetfs_fill_super() passes NULL, since dev_data is unaffected
by this fix.
Reported-by: syzbot+df9e891bf8ea586f846b@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=df9e891bf8ea586f846b
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
drivers/usb/gadget/legacy/inode.c | 51 +++++++++++++++++++++----------
1 file changed, 35 insertions(+), 16 deletions(-)
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
index d87a8ab51510..f566b2ec7c38 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -207,6 +207,7 @@ struct ep_data {
struct usb_endpoint_descriptor desc, hs_desc;
struct list_head epfiles;
wait_queue_head_t wait;
+ struct inode *inode;
};
static inline void get_ep (struct ep_data *data)
@@ -235,6 +236,7 @@ static void put_ep (struct ep_data *data)
static const char *CHIP;
static DEFINE_MUTEX(sb_mutex); /* Serialize superblock operations */
+static struct dev_data *the_device;
/*----------------------------------------------------------------------*/
@@ -817,25 +819,39 @@ ep_config (struct ep_data *data, const char *buf, size_t len)
static int
ep_open (struct inode *inode, struct file *fd)
{
- struct ep_data *data = inode->i_private;
- int value = -EBUSY;
+ struct dev_data *dev = the_device;
+ struct ep_data *data;
+ int value = -ENODEV;
+
+ spin_lock_irq (&dev->lock);
+ data = inode->i_private;
+ if (data == NULL) {
+ spin_unlock_irq (&dev->lock);
+ return -ENOENT;
+ }
+ get_ep (data);
+ spin_unlock_irq (&dev->lock);
- if (mutex_lock_interruptible(&data->lock) != 0)
+ if (mutex_lock_interruptible(&data->lock) != 0) {
+ put_ep (data);
return -EINTR;
- spin_lock_irq (&data->dev->lock);
- if (data->dev->state == STATE_DEV_UNBOUND)
+ }
+
+ value = -EBUSY;
+ spin_lock_irq (&dev->lock);
+ if (dev->state == STATE_DEV_UNBOUND)
value = -ENOENT;
else if (data->state == STATE_EP_DISABLED) {
value = 0;
data->state = STATE_EP_READY;
- get_ep (data);
fd->private_data = data;
- VDEBUG (data->dev, "%s ready\n", data->name);
+ VDEBUG (dev, "%s ready\n", data->name);
} else
- DBG (data->dev, "%s state %d\n",
- data->name, data->state);
- spin_unlock_irq (&data->dev->lock);
+ DBG (dev, "%s state %d\n", data->name, data->state);
+ spin_unlock_irq (&dev->lock);
mutex_unlock(&data->lock);
+ if (value)
+ put_ep (data);
return value;
}
@@ -1563,6 +1579,7 @@ static void destroy_ep_files (struct dev_data *dev)
/* break link to FS */
ep = list_first_entry (&dev->epfiles, struct ep_data, epfiles);
list_del_init (&ep->epfiles);
+ ep->inode->i_private = NULL;
spin_unlock_irq (&dev->lock);
/* break link to controller */
@@ -1588,7 +1605,8 @@ static void destroy_ep_files (struct dev_data *dev)
static int gadgetfs_create_file (struct super_block *sb, char const *name,
- void *data, const struct file_operations *fops);
+ void *data, const struct file_operations *fops,
+ struct inode **inode_out);
static int activate_ep_files (struct dev_data *dev)
{
@@ -1618,7 +1636,7 @@ static int activate_ep_files (struct dev_data *dev)
goto enomem1;
err = gadgetfs_create_file (dev->sb, data->name,
- data, &ep_io_operations);
+ data, &ep_io_operations, &data->inode);
if (err)
goto enomem2;
list_add_tail (&data->epfiles, &dev->epfiles);
@@ -1663,8 +1681,6 @@ gadgetfs_unbind (struct usb_gadget *gadget)
put_dev (dev);
}
-static struct dev_data *the_device;
-
static int gadgetfs_bind(struct usb_gadget *gadget,
struct usb_gadget_driver *driver)
{
@@ -1984,7 +2000,7 @@ gadgetfs_make_inode (struct super_block *sb,
* so inode and dentry are paired, until device reconfig.
*/
static int gadgetfs_create_file (struct super_block *sb, char const *name,
- void *data, const struct file_operations *fops)
+ void *data, const struct file_operations *fops, struct inode **inode_out)
{
struct dentry *dentry;
struct inode *inode;
@@ -1994,6 +2010,9 @@ static int gadgetfs_create_file (struct super_block *sb, char const *name,
if (!inode)
return -ENOMEM;
+ if(inode_out)
+ *inode_out = inode;
+
dentry = simple_start_creating(sb->s_root, name);
if (IS_ERR(dentry)) {
iput(inode);
@@ -2056,7 +2075,7 @@ gadgetfs_fill_super (struct super_block *sb, struct fs_context *fc)
goto Enomem;
dev->sb = sb;
- rc = gadgetfs_create_file(sb, CHIP, dev, &ep0_operations);
+ rc = gadgetfs_create_file(sb, CHIP, dev, &ep0_operations, NULL);
if (rc) {
put_dev(dev);
goto Enomem;
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* Forwarded: [PATCH v2] usb: gadgetfs: fix use-after-free in ep_open()
2026-07-31 1:28 [syzbot] [usb?] KASAN: slab-use-after-free Read in ep_open syzbot
` (2 preceding siblings ...)
2026-07-31 8:09 ` syzbot
@ 2026-07-31 11:40 ` syzbot
2026-08-17 13:42 ` [syzbot] [usb?] KASAN: slab-use-after-free Read in ep_open syzbot
4 siblings, 0 replies; 15+ messages in thread
From: syzbot @ 2026-07-31 11:40 UTC (permalink / raw)
To: linux-kernel, syzkaller-bugs
For archival purposes, forwarding an incoming command email to
linux-kernel@vger.kernel.org, syzkaller-bugs@googlegroups.com.
***
Subject: [PATCH v2] usb: gadgetfs: fix use-after-free in ep_open()
Author: kartikey406@gmail.com
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-kernelci
ep_open() dereferenced inode->i_private and locked its embedded
mutex before checking whether the underlying ep_data was still
alive. destroy_ep_files(), called from gadgetfs_unbind(), can free
that same ep_data concurrently, since nothing prevented an in-flight
open() from racing the teardown. KASAN reports a slab-use-after-free
in ep_open(), with the object freed by a concurrent gadgetfs_unbind()
-> destroy_ep_files() -> put_ep() -> kfree().
Fix it by adding an inode back-pointer to ep_data, having
destroy_ep_files() clear inode->i_private to NULL under dev->lock
before the object can be freed, and having ep_open() read
inode->i_private and pin the result with get_ep() under that same
lock, bailing out with -ENOENT if it finds NULL. This makes liveness
self-evident at the point of use instead of being inferred from
device state, so it holds regardless of which path frees the
endpoint.
dev is derived from inode->i_sb->s_fs_info, set in
gadgetfs_fill_super(), rather than from the file's the_device
singleton, so ep_open() is correctly scoped to the specific mount
the inode belongs to.
gadgetfs_create_file() now returns the created inode (or an
ERR_PTR) directly instead of taking an output parameter, so
activate_ep_files() can store it in data->inode without an
unexplained NULL at call sites that don't need it.
Reported-by: syzbot+df9e891bf8ea586f846b@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=df9e891bf8ea586f846b
Fixes: 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 ("Linux-2.6.12-rc2")
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
---
v2:
- Added Fixes: tag; git blame traces the bug to the 2005 git
import boundary, confirmed no later commit changed the ordering
- Derive dev from inode->i_sb->s_fs_info instead of the new
the_device singleton, so the lookup is scoped to the inode's
own mount instead of a global (Greg)
- gadgetfs_create_file() now returns struct inode * / ERR_PTR
instead of taking an inode_out output parameter, so call sites
don't need an unexplained NULL argument (Greg)
---
drivers/usb/gadget/legacy/inode.c | 61 ++++++++++++++++++++-----------
1 file changed, 39 insertions(+), 22 deletions(-)
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
index d87a8ab51510..e5a316777db2 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -207,6 +207,7 @@ struct ep_data {
struct usb_endpoint_descriptor desc, hs_desc;
struct list_head epfiles;
wait_queue_head_t wait;
+ struct inode *inode;
};
static inline void get_ep (struct ep_data *data)
@@ -235,6 +236,7 @@ static void put_ep (struct ep_data *data)
static const char *CHIP;
static DEFINE_MUTEX(sb_mutex); /* Serialize superblock operations */
+static struct dev_data *the_device;
/*----------------------------------------------------------------------*/
@@ -817,25 +819,39 @@ ep_config (struct ep_data *data, const char *buf, size_t len)
static int
ep_open (struct inode *inode, struct file *fd)
{
- struct ep_data *data = inode->i_private;
- int value = -EBUSY;
+ struct dev_data *dev = inode->i_sb->s_fs_info;
+ struct ep_data *data;
+ int value = -ENODEV;
+
+ spin_lock_irq (&dev->lock);
+ data = inode->i_private;
+ if (data == NULL) {
+ spin_unlock_irq (&dev->lock);
+ return -ENOENT;
+ }
+ get_ep (data);
+ spin_unlock_irq (&dev->lock);
- if (mutex_lock_interruptible(&data->lock) != 0)
+ if (mutex_lock_interruptible(&data->lock) != 0) {
+ put_ep (data);
return -EINTR;
- spin_lock_irq (&data->dev->lock);
- if (data->dev->state == STATE_DEV_UNBOUND)
+ }
+
+ value = -EBUSY;
+ spin_lock_irq (&dev->lock);
+ if (dev->state == STATE_DEV_UNBOUND)
value = -ENOENT;
else if (data->state == STATE_EP_DISABLED) {
value = 0;
data->state = STATE_EP_READY;
- get_ep (data);
fd->private_data = data;
- VDEBUG (data->dev, "%s ready\n", data->name);
+ VDEBUG (dev, "%s ready\n", data->name);
} else
- DBG (data->dev, "%s state %d\n",
- data->name, data->state);
- spin_unlock_irq (&data->dev->lock);
+ DBG (dev, "%s state %d\n", data->name, data->state);
+ spin_unlock_irq (&dev->lock);
mutex_unlock(&data->lock);
+ if (value)
+ put_ep (data);
return value;
}
@@ -1563,6 +1579,7 @@ static void destroy_ep_files (struct dev_data *dev)
/* break link to FS */
ep = list_first_entry (&dev->epfiles, struct ep_data, epfiles);
list_del_init (&ep->epfiles);
+ ep->inode->i_private = NULL;
spin_unlock_irq (&dev->lock);
/* break link to controller */
@@ -1587,14 +1604,13 @@ static void destroy_ep_files (struct dev_data *dev)
}
-static int gadgetfs_create_file (struct super_block *sb, char const *name,
+static struct inode *gadgetfs_create_file (struct super_block *sb, char const *name,
void *data, const struct file_operations *fops);
static int activate_ep_files (struct dev_data *dev)
{
struct usb_ep *ep;
struct ep_data *data;
- int err;
gadget_for_each_ep (ep, dev->gadget) {
@@ -1617,9 +1633,9 @@ static int activate_ep_files (struct dev_data *dev)
if (!data->req)
goto enomem1;
- err = gadgetfs_create_file (dev->sb, data->name,
+ data->inode = gadgetfs_create_file (dev->sb, data->name,
data, &ep_io_operations);
- if (err)
+ if (IS_ERR(data->inode))
goto enomem2;
list_add_tail (&data->epfiles, &dev->epfiles);
}
@@ -1663,8 +1679,6 @@ gadgetfs_unbind (struct usb_gadget *gadget)
put_dev (dev);
}
-static struct dev_data *the_device;
-
static int gadgetfs_bind(struct usb_gadget *gadget,
struct usb_gadget_driver *driver)
{
@@ -1983,7 +1997,7 @@ gadgetfs_make_inode (struct super_block *sb,
/* creates in fs root directory, so non-renamable and non-linkable.
* so inode and dentry are paired, until device reconfig.
*/
-static int gadgetfs_create_file (struct super_block *sb, char const *name,
+static struct inode *gadgetfs_create_file (struct super_block *sb, char const *name,
void *data, const struct file_operations *fops)
{
struct dentry *dentry;
@@ -1992,18 +2006,18 @@ static int gadgetfs_create_file (struct super_block *sb, char const *name,
inode = gadgetfs_make_inode (sb, data, fops,
S_IFREG | (default_perm & S_IRWXUGO));
if (!inode)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
dentry = simple_start_creating(sb->s_root, name);
if (IS_ERR(dentry)) {
iput(inode);
- return PTR_ERR(dentry);
+ return ERR_CAST(dentry);
}
d_make_persistent(dentry, inode);
simple_done_creating(dentry);
- return 0;
+ return inode;
}
static const struct super_operations gadget_fs_operations = {
@@ -2056,8 +2070,11 @@ gadgetfs_fill_super (struct super_block *sb, struct fs_context *fc)
goto Enomem;
dev->sb = sb;
- rc = gadgetfs_create_file(sb, CHIP, dev, &ep0_operations);
- if (rc) {
+ sb->s_fs_info = dev;
+ inode = gadgetfs_create_file(sb, CHIP, dev, &ep0_operations);
+ if (IS_ERR(inode)) {
+ rc = PTR_ERR(inode);
+ sb->s_fs_info = NULL;
put_dev(dev);
goto Enomem;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [syzbot] [usb?] KASAN: slab-use-after-free Read in ep_open
2026-07-31 1:28 [syzbot] [usb?] KASAN: slab-use-after-free Read in ep_open syzbot
` (3 preceding siblings ...)
2026-07-31 11:40 ` Forwarded: [PATCH v2] " syzbot
@ 2026-08-17 13:42 ` syzbot
2026-08-17 15:04 ` Jens Axboe
4 siblings, 1 reply; 15+ messages in thread
From: syzbot @ 2026-08-17 13:42 UTC (permalink / raw)
To: asml.silence, axboe, brauner, gregkh, io-uring, jack, kartikey406,
kees, linux-kernel, linux-usb, mjguzik, nogikh, stern, syzbot,
syzbot, syzkaller-bugs, syzkaller-upstream-moderation, torvalds,
viro
syzbot has bisected this issue to:
commit aa00f67adc2c0d6439f81b5a81ff181377c47a7e
Author: Jens Axboe <axboe@kernel.dk>
Date: Tue Oct 22 19:47:00 2024 +0000
io_uring: add support for fixed wait regions
bisection log: https://syzkaller.appspot.com/x/bisect.txt?x=10e60679580000
start commit: 9a143525f62b Merge tag 'ata-7.2-rc7' of git://git.kernel.o..
git tree: upstream
final oops: https://syzkaller.appspot.com/x/report.txt?x=12e60679580000
console output: https://syzkaller.appspot.com/x/log.txt?x=14e60679580000
kernel config: https://syzkaller.appspot.com/x/.config?x=c44651ea7dd2f307
dashboard link: https://syzkaller.appspot.com/bug?extid=df9e891bf8ea586f846b
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=120defb9580000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=16323fb9580000
Reported-by: syzbot+df9e891bf8ea586f846b@syzkaller.appspotmail.com
Fixes: aa00f67adc2c ("io_uring: add support for fixed wait regions")
For information about bisection process see: https://goo.gl/tpsmEJ#bisection
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [syzbot] [usb?] KASAN: slab-use-after-free Read in ep_open
2026-08-17 13:42 ` [syzbot] [usb?] KASAN: slab-use-after-free Read in ep_open syzbot
@ 2026-08-17 15:04 ` Jens Axboe
2026-08-17 15:45 ` Alan Stern
0 siblings, 1 reply; 15+ messages in thread
From: Jens Axboe @ 2026-08-17 15:04 UTC (permalink / raw)
To: syzbot, asml.silence, brauner, gregkh, io-uring, jack,
kartikey406, kees, linux-kernel, linux-usb, mjguzik, nogikh,
stern, syzbot, syzbot, syzkaller-bugs,
syzkaller-upstream-moderation, torvalds, viro
On 8/17/26 7:42 AM, syzbot wrote:
> syzbot has bisected this issue to:
>
> commit aa00f67adc2c0d6439f81b5a81ff181377c47a7e
> Author: Jens Axboe <axboe@kernel.dk>
> Date: Tue Oct 22 19:47:00 2024 +0000
>
> io_uring: add support for fixed wait regions
>
> bisection log: https://syzkaller.appspot.com/x/bisect.txt?x=10e60679580000
> start commit: 9a143525f62b Merge tag 'ata-7.2-rc7' of git://git.kernel.o..
> git tree: upstream
> final oops: https://syzkaller.appspot.com/x/report.txt?x=12e60679580000
> console output: https://syzkaller.appspot.com/x/log.txt?x=14e60679580000
> kernel config: https://syzkaller.appspot.com/x/.config?x=c44651ea7dd2f307
> dashboard link: https://syzkaller.appspot.com/bug?extid=df9e891bf8ea586f846b
> syz repro: https://syzkaller.appspot.com/x/repro.syz?x=120defb9580000
> C reproducer: https://syzkaller.appspot.com/x/repro.c?x=16323fb9580000
>
> Reported-by: syzbot+df9e891bf8ea586f846b@syzkaller.appspotmail.com
> Fixes: aa00f67adc2c ("io_uring: add support for fixed wait regions")
That looks like nonsense, I strongly suspect it's a race and hence your
bisection ends up being mostly useless as it sends you in random directions.
--
Jens Axboe
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [syzbot] [usb?] KASAN: slab-use-after-free Read in ep_open
2026-08-17 15:04 ` Jens Axboe
@ 2026-08-17 15:45 ` Alan Stern
2026-08-17 16:38 ` syzbot
0 siblings, 1 reply; 15+ messages in thread
From: Alan Stern @ 2026-08-17 15:45 UTC (permalink / raw)
To: Jens Axboe
Cc: syzbot, asml.silence, brauner, gregkh, io-uring, jack,
kartikey406, kees, linux-kernel, linux-usb, mjguzik, nogikh,
syzbot, syzbot, syzkaller-bugs, syzkaller-upstream-moderation,
torvalds, viro
On Mon, Aug 17, 2026 at 09:04:06AM -0600, Jens Axboe wrote:
> On 8/17/26 7:42 AM, syzbot wrote:
> > syzbot has bisected this issue to:
> >
> > commit aa00f67adc2c0d6439f81b5a81ff181377c47a7e
> > Author: Jens Axboe <axboe@kernel.dk>
> > Date: Tue Oct 22 19:47:00 2024 +0000
> >
> > io_uring: add support for fixed wait regions
> >
> > bisection log: https://syzkaller.appspot.com/x/bisect.txt?x=10e60679580000
> > start commit: 9a143525f62b Merge tag 'ata-7.2-rc7' of git://git.kernel.o..
> > git tree: upstream
> > final oops: https://syzkaller.appspot.com/x/report.txt?x=12e60679580000
> > console output: https://syzkaller.appspot.com/x/log.txt?x=14e60679580000
> > kernel config: https://syzkaller.appspot.com/x/.config?x=c44651ea7dd2f307
> > dashboard link: https://syzkaller.appspot.com/bug?extid=df9e891bf8ea586f846b
> > syz repro: https://syzkaller.appspot.com/x/repro.syz?x=120defb9580000
> > C reproducer: https://syzkaller.appspot.com/x/repro.c?x=16323fb9580000
> >
> > Reported-by: syzbot+df9e891bf8ea586f846b@syzkaller.appspotmail.com
> > Fixes: aa00f67adc2c ("io_uring: add support for fixed wait regions")
>
> That looks like nonsense, I strongly suspect it's a race and hence your
> bisection ends up being mostly useless as it sends you in random directions.
Agreed.
The patch below has already been sent to the USB mailing list. Has
syzbot tested it?
Alan Stern
#syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ v7.2
From: Aleksandr Nogikh <nogikh@google.com>
A race condition exists between opening a gadgetfs endpoint file and the
destruction of the endpoint files, leading to a use-after-free of the
ep_data object.
When an endpoint file is opened, the VFS looks up the dentry and calls
ep_open(). ep_open() retrieves the ep_data pointer from inode->i_private
and attempts to lock its mutex. Concurrently, if the gadget is unbound,
destroy_ep_files() iterates over the endpoints, unhashes their dentries,
and immediately calls put_ep(). This drops the initial reference to the
ep_data object, freeing it. If another thread is already in the process of
opening the file, it holds a reference to the dentry and the inode. The
inode remains alive, and its i_private pointer still points to the
now-freed ep_data. When ep_open() proceeds to lock data->lock, it accesses
freed memory.
BUG: KASAN: slab-use-after-free in __mutex_lock_common
kernel/locking/mutex.c:625 [inline]
BUG: KASAN: slab-use-after-free in __mutex_lock+0x130/0xf14
kernel/locking/mutex.c:821
Read of size 8 at addr ffff0000f43acc58 by task syz-executor/5900
Call trace:
__mutex_lock_common kernel/locking/mutex.c:625 [inline]
__mutex_lock+0x130/0xf14 kernel/locking/mutex.c:821
mutex_lock_interruptible_nested+0x24/0x30 kernel/locking/mutex.c:899
ep_open+0x58/0x25c drivers/usb/gadget/legacy/inode.c:823
do_dentry_open+0x5c4/0xfc0 fs/open.c:947
vfs_open+0x44/0x2dc fs/open.c:1052
Freed by task 6138:
kfree+0x188/0x690 mm/slub.c:6692
put_ep+0xd0/0x144 drivers/usb/gadget/legacy/inode.c:225
destroy_ep_files+0x244/0x2dc drivers/usb/gadget/legacy/inode.c:1582
gadgetfs_unbind+0x114/0x1f0 drivers/usb/gadget/legacy/inode.c:1655
gadget_unbind_driver+0x188/0x790 drivers/usb/gadget/udc/core.c:1724
To fix this, tie the base reference of ep_data to the lifetime of the inode
rather than manually dropping it in destroy_ep_files(). Add an .evict_inode
callback to gadget_fs_operations that drops the reference when the inode is
finally destroyed. Remove the premature put_ep() call from
destroy_ep_files(). Additionally, to prevent a double-free in the error
path of activate_ep_files(), clear inode->i_private in
gadgetfs_create_file() before calling iput() if simple_start_creating()
fails.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Assisted-by: Gemini:gemini-3.5-flash Gemini:gemini-3.1-pro-preview syzbot
Reported-by: syzbot+df9e891bf8ea586f846b@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=df9e891bf8ea586f846b
Link: https://syzkaller.appspot.com/ai_job?id=ae49a838-5eb9-4227-93a3-56ad2313483a
Signed-off-by: Aleksandr Nogikh <nogikh@google.com>
---
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
index d87a8ab51..a03062986 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -1579,8 +1579,6 @@ static void destroy_ep_files (struct dev_data *dev)
/* break link to dcache */
simple_remove_by_name(dev->sb->s_root, ep->name, NULL);
- put_ep (ep);
-
spin_lock_irq (&dev->lock);
}
spin_unlock_irq (&dev->lock);
@@ -1996,6 +1994,7 @@ static int gadgetfs_create_file (struct super_block *sb, char const *name,
dentry = simple_start_creating(sb->s_root, name);
if (IS_ERR(dentry)) {
+ inode->i_private = NULL;
iput(inode);
return PTR_ERR(dentry);
}
@@ -2006,9 +2005,18 @@ static int gadgetfs_create_file (struct super_block *sb, char const *name,
return 0;
}
+static void gadgetfs_evict_inode(struct inode *inode)
+{
+ truncate_inode_pages_final(&inode->i_data);
+ clear_inode(inode);
+ if (inode->i_private && inode->i_fop == &ep_io_operations)
+ put_ep(inode->i_private);
+}
+
static const struct super_operations gadget_fs_operations = {
.statfs = simple_statfs,
.drop_inode = inode_just_drop,
+ .evict_inode = gadgetfs_evict_inode,
};
static int
base-commit: f5098b6bae761e346ebcd9da7f95622c04733cff
--
See https://goo.gle/syzbot-ai-patches for information about AI-generated patches.
You can comment on the patch as usual, syzbot will try to address
the comments and send a new version of the patch if necessary.
syzbot engineers can be reached at syzkaller@googlegroups.com.
^ permalink raw reply related [flat|nested] 15+ messages in thread* Re: [syzbot] [usb?] KASAN: slab-use-after-free Read in ep_open
2026-08-17 15:45 ` Alan Stern
@ 2026-08-17 16:38 ` syzbot
2026-08-17 18:14 ` Alan Stern
0 siblings, 1 reply; 15+ messages in thread
From: syzbot @ 2026-08-17 16:38 UTC (permalink / raw)
To: asml.silence, axboe, brauner, gregkh, io-uring, jack, kartikey406,
kees, linux-kernel, linux-usb, mjguzik, nogikh, stern, syzbot,
syzbot, syzkaller-bugs, syzkaller-upstream-moderation, torvalds,
viro
Hello,
syzbot has tested the proposed patch and the reproducer did not trigger any issue:
Reported-by: syzbot+df9e891bf8ea586f846b@syzkaller.appspotmail.com
Tested-by: syzbot+df9e891bf8ea586f846b@syzkaller.appspotmail.com
Tested on:
commit: 8d3ae592 Linux 7.2
git tree: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ v7.2
console output: https://syzkaller.appspot.com/x/log.txt?x=16a91a25580000
kernel config: https://syzkaller.appspot.com/x/.config?x=c44651ea7dd2f307
dashboard link: https://syzkaller.appspot.com/bug?extid=df9e891bf8ea586f846b
compiler: gcc (Debian 14.2.0-19) 14.2.0, GNU ld (GNU Binutils for Debian) 2.44
patch: https://syzkaller.appspot.com/x/patch.diff?x=15790679580000
Note: testing is done by a robot and is best-effort only.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [syzbot] [usb?] KASAN: slab-use-after-free Read in ep_open
2026-08-17 16:38 ` syzbot
@ 2026-08-17 18:14 ` Alan Stern
2026-08-18 7:42 ` Greg KH
0 siblings, 1 reply; 15+ messages in thread
From: Alan Stern @ 2026-08-17 18:14 UTC (permalink / raw)
To: Greg KH
Cc: syzbot, asml.silence, axboe, brauner, io-uring, jack, kartikey406,
kees, linux-kernel, linux-usb, mjguzik, nogikh, syzbot, syzbot,
syzkaller-bugs, syzkaller-upstream-moderation, torvalds, viro
On Mon, Aug 17, 2026 at 09:38:02AM -0700, syzbot wrote:
> Hello,
>
> syzbot has tested the proposed patch and the reproducer did not trigger any issue:
>
> Reported-by: syzbot+df9e891bf8ea586f846b@syzkaller.appspotmail.com
> Tested-by: syzbot+df9e891bf8ea586f846b@syzkaller.appspotmail.com
>
> Tested on:
>
> commit: 8d3ae592 Linux 7.2
> git tree: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ v7.2
> console output: https://syzkaller.appspot.com/x/log.txt?x=16a91a25580000
> kernel config: https://syzkaller.appspot.com/x/.config?x=c44651ea7dd2f307
> dashboard link: https://syzkaller.appspot.com/bug?extid=df9e891bf8ea586f846b
> compiler: gcc (Debian 14.2.0-19) 14.2.0, GNU ld (GNU Binutils for Debian) 2.44
> patch: https://syzkaller.appspot.com/x/patch.diff?x=15790679580000
>
> Note: testing is done by a robot and is best-effort only.
Greg:
Has this patch ever been queued?
https://lore.kernel.org/linux-usb/ee41fbfd-f368-4a06-95d6-ae9b4267fd82@mail.kernel.org/
Looks like you can add syzbot's Tested-by: tag, as well as my Acked-by:.
Note that a different patch to fix the same problem was submitted here:
https://lore.kernel.org/linux-usb/20260731230603.4637-1-kartikey406@gmail.com/
IMO the first patch above is superior.
Alan Stern
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [syzbot] [usb?] KASAN: slab-use-after-free Read in ep_open
2026-08-17 18:14 ` Alan Stern
@ 2026-08-18 7:42 ` Greg KH
0 siblings, 0 replies; 15+ messages in thread
From: Greg KH @ 2026-08-18 7:42 UTC (permalink / raw)
To: Alan Stern
Cc: syzbot, asml.silence, axboe, brauner, io-uring, jack, kartikey406,
kees, linux-kernel, linux-usb, mjguzik, nogikh, syzbot, syzbot,
syzkaller-bugs, syzkaller-upstream-moderation, torvalds, viro
On Mon, Aug 17, 2026 at 02:14:17PM -0400, Alan Stern wrote:
> On Mon, Aug 17, 2026 at 09:38:02AM -0700, syzbot wrote:
> > Hello,
> >
> > syzbot has tested the proposed patch and the reproducer did not trigger any issue:
> >
> > Reported-by: syzbot+df9e891bf8ea586f846b@syzkaller.appspotmail.com
> > Tested-by: syzbot+df9e891bf8ea586f846b@syzkaller.appspotmail.com
> >
> > Tested on:
> >
> > commit: 8d3ae592 Linux 7.2
> > git tree: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/ v7.2
> > console output: https://syzkaller.appspot.com/x/log.txt?x=16a91a25580000
> > kernel config: https://syzkaller.appspot.com/x/.config?x=c44651ea7dd2f307
> > dashboard link: https://syzkaller.appspot.com/bug?extid=df9e891bf8ea586f846b
> > compiler: gcc (Debian 14.2.0-19) 14.2.0, GNU ld (GNU Binutils for Debian) 2.44
> > patch: https://syzkaller.appspot.com/x/patch.diff?x=15790679580000
> >
> > Note: testing is done by a robot and is best-effort only.
>
> Greg:
>
> Has this patch ever been queued?
>
> https://lore.kernel.org/linux-usb/ee41fbfd-f368-4a06-95d6-ae9b4267fd82@mail.kernel.org/
No because it looks like there are competing patches here as you point
out.
> Looks like you can add syzbot's Tested-by: tag, as well as my Acked-by:.
>
> Note that a different patch to fix the same problem was submitted here:
>
> https://lore.kernel.org/linux-usb/20260731230603.4637-1-kartikey406@gmail.com/
>
> IMO the first patch above is superior.
So Aleksandr's patch should be applied and not Deepanshu's?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 15+ messages in thread