[PATCH RFC] usb: gadgetfs: fix unbalanced refcount in gadgetfs_bind() error path
"syzbot" <[email protected]> Fri, 31 Jul 2026 07:56:04 +0000 (UTC)
| Newsgroups | dev.linux.lists.syzbot |
|---|---|
| Message-ID | <[email protected]> |
A KASAN slab-use-after-free can occur in gadget_dev_open() due to an
unbalanced reference count in the error path of gadgetfs_bind().
When gadgetfs_bind() is called, it performs several initialization steps.
If it succeeds, it takes a reference to the dev object by calling
get_dev(dev) at the very end of the function. This reference is meant to be
balanced by a call to put_dev(dev) inside gadgetfs_unbind() when the driver
is eventually unbound.
However, if gadgetfs_bind() fails midway (e.g., due to a memory allocation
failure in usb_ep_alloc_request() or activate_ep_files()), it jumps to the
enomem label and calls gadgetfs_unbind(gadget). Because get_dev(dev) was
never called, gadgetfs_unbind() drops a reference that was never acquired.
This leads to the dev object being freed prematurely when the file
descriptor is closed, resulting in a use-after-free when the file is opened
again.
BUG: KASAN: slab-use-after-free in __raw_spin_lock_irq
include/linux/spinlock_api_smp.h:142 [inline]
BUG: KASAN: slab-use-after-free in _raw_spin_lock_irq+0x58/0x70
kernel/locking/spinlock.c:174
Read of size 1 at addr ffff0000dbe16018 by task syz.0.18/5334
...
Call trace:
...
__raw_spin_lock_irq include/linux/spinlock_api_smp.h:142 [inline]
_raw_spin_lock_irq+0x58/0x70 kernel/locking/spinlock.c:174
spin_lock_irq include/linux/spinlock.h:372 [inline]
gadget_dev_open+0x50/0x1c4 drivers/usb/gadget/legacy/inode.c:1919
do_dentry_open+0x5c4/0xfc0 fs/open.c:947
vfs_open+0x44/0x2dc fs/open.c:1052
To fix this, replace the monolithic gadgetfs_unbind() call in the enomem
error path with manual, step-by-step cleanup of exactly the resources that
were allocated prior to the failure. If dev->req was allocated, it is freed
and set to NULL. The gadget data pointers (gadget->ep0->driver_data,
dev->gadget, and set_gadget_data) are cleared. Note that
activate_ep_files() already cleans up after itself if it fails, so we don't
need to manually undo its effects.
This ensures that only the resources actually allocated by gadgetfs_bind()
are cleaned up, preventing the unbalanced put_dev() and incorrect state
changes that caused the use-after-free.
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Assisted-by: Gemini:gemini-3.5-flash Gemini:gemini-3.1-pro-preview syzbot
Reported-by: [email protected]
Closes: https://syzkaller.appspot.com/bug?extid=1459655b2bf1e798f9d0
Link: https://syzkaller.appspot.com/ai_job?id=992d95f0-8de6-44af-9ebe-f7c976f4ba68
To: "Greg Kroah-Hartman" <[email protected]>
To: <[email protected]>
To: "Linus Torvalds" <[email protected]>
Cc: "Christian Brauner" <[email protected]>
Cc: "Jan Kara" <[email protected]>
Cc: "Kees Cook" <[email protected]>
Cc: <[email protected]>
Cc: "Mateusz Guzik" <[email protected]>
Cc: "Al Viro" <[email protected]>
---
diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
index d87a8ab51..365f9ab4d 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -1700,7 +1700,13 @@ static int gadgetfs_bind(struct usb_gadget *gadget,
return 0;
enomem:
- gadgetfs_unbind (gadget);
+ if (dev->req) {
+ usb_ep_free_request(gadget->ep0, dev->req);
+ dev->req = NULL;
+ }
+ gadget->ep0->driver_data = NULL;
+ dev->gadget = NULL;
+ set_gadget_data(gadget, NULL);
return -ENOMEM;
}
base-commit: f5098b6bae761e346ebcd9da7f95622c04733cff
--
This is an AI-generated patch subject to moderation.
Reply with '#syz upstream' to Sign-off the patch as a human author
and send it to the upstream kernel mailing lists.
Reply with '#syz reject' to reject it ('#syz unreject' to undo).
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 [email protected].