[PATCH] usb: gadget: fix refcount underflow in gadgetfs_bind() error path

Nguyen Quang Le Kien posted 1 patch 1 month, 2 weeks ago
drivers/usb/gadget/legacy/inode.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
[PATCH] usb: gadget: fix refcount underflow in gadgetfs_bind() error path
Posted by Nguyen Quang Le Kien 1 month, 2 weeks ago
gadgetfs_bind() calls get_dev() only on the success path, but
gadgetfs_unbind() called from the enomem error label unconditionally
calls put_dev().  When bind fails (e.g. ENOMEM), put_dev() fires
without a matching get_dev(), leaving the refcount unbalanced.

A subsequent close of the ep0 file descriptor calls dev_release() ->
put_dev() which hits zero and frees the object; then gadgetfs_kill_sb()
calls put_dev(the_device) again on the already-freed pointer, triggering
a refcount underflow and use-after-free.

Fix by calling get_dev() at the start of gadgetfs_bind(), before any
error path that invokes gadgetfs_unbind(), so the reference is always
balanced regardless of whether bind succeeds or fails.

Reported-by: syzbot+8496ab5e117502750445@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=8496ab5e117502750445
Signed-off-by: Nguyen Quang Le Kien <khiemtranzo532001@gmail.com>
---
 drivers/usb/gadget/legacy/inode.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
index d87a8ab51..d6551a4ce 100644
--- a/drivers/usb/gadget/legacy/inode.c
+++ b/drivers/usb/gadget/legacy/inode.c
@@ -1682,6 +1682,8 @@ static int gadgetfs_bind(struct usb_gadget *gadget,
 	dev->gadget = gadget;
 	gadget->ep0->driver_data = dev;
 
+	get_dev (dev);
+
 	/* preallocate control response and buffer */
 	dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
 	if (!dev->req)
@@ -1696,7 +1698,6 @@ static int gadgetfs_bind(struct usb_gadget *gadget,
 	spin_lock_irq(&dev->lock);
 	dev->state = STATE_DEV_UNCONNECTED;
 	spin_unlock_irq(&dev->lock);
-	get_dev (dev);
 	return 0;
 
 enomem:
-- 
2.34.1
Re: [PATCH] usb: gadget: fix refcount underflow in gadgetfs_bind() error path
Posted by Alan Stern 1 month, 2 weeks ago
On Tue, Aug 11, 2026 at 02:08:10PM +0800, Nguyen Quang Le Kien wrote:
> gadgetfs_bind() calls get_dev() only on the success path, but
> gadgetfs_unbind() called from the enomem error label unconditionally
> calls put_dev().  When bind fails (e.g. ENOMEM), put_dev() fires
> without a matching get_dev(), leaving the refcount unbalanced.
> 
> A subsequent close of the ep0 file descriptor calls dev_release() ->
> put_dev() which hits zero and frees the object; then gadgetfs_kill_sb()
> calls put_dev(the_device) again on the already-freed pointer, triggering
> a refcount underflow and use-after-free.
> 
> Fix by calling get_dev() at the start of gadgetfs_bind(), before any
> error path that invokes gadgetfs_unbind(), so the reference is always
> balanced regardless of whether bind succeeds or fails.
> 
> Reported-by: syzbot+8496ab5e117502750445@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=8496ab5e117502750445
> Signed-off-by: Nguyen Quang Le Kien <khiemtranzo532001@gmail.com>
> ---

Reviewed-by: Alan Stern <stern@rowland.harvard.edu>

>  drivers/usb/gadget/legacy/inode.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c
> index d87a8ab51..d6551a4ce 100644
> --- a/drivers/usb/gadget/legacy/inode.c
> +++ b/drivers/usb/gadget/legacy/inode.c
> @@ -1682,6 +1682,8 @@ static int gadgetfs_bind(struct usb_gadget *gadget,
>  	dev->gadget = gadget;
>  	gadget->ep0->driver_data = dev;
>  
> +	get_dev (dev);
> +
>  	/* preallocate control response and buffer */
>  	dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
>  	if (!dev->req)
> @@ -1696,7 +1698,6 @@ static int gadgetfs_bind(struct usb_gadget *gadget,
>  	spin_lock_irq(&dev->lock);
>  	dev->state = STATE_DEV_UNCONNECTED;
>  	spin_unlock_irq(&dev->lock);
> -	get_dev (dev);
>  	return 0;
>  
>  enomem:
> -- 
> 2.34.1
> 
>