[PATCH RFC] usb: gadgetfs: fix reference count underflow in gadgetfs_bind()

"syzbot" <[email protected]>
Newsgroups dev.linux.lists.syzbot
Message-ID <[email protected]>
A KASAN slab-use-after-free bug was found in gadgetfs_kill_sb():

BUG: KASAN: slab-use-after-free in put_dev
drivers/usb/gadget/legacy/inode.c:165 [inline]
BUG: KASAN: slab-use-after-free in gadgetfs_kill_sb+0x46/0x110
drivers/usb/gadget/legacy/inode.c:2104
Write of size 4 at addr ffff88811638c080 by task syz-executor169/5848

CPU: 0 UID: 0 PID: 5848 Comm: syz-executor169 Not tainted
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS
1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
 <TASK>
 dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
 print_address_description+0x55/0x1e0 mm/kasan/report.c:378
 print_report+0x58/0x70 mm/kasan/report.c:482
 kasan_report+0x117/0x150 mm/kasan/report.c:595
 check_region_inline mm/kasan/generic.c:-1 [inline]
 kasan_check_range+0x264/0x2c0 mm/kasan/generic.c:200
 instrument_atomic_read_write include/linux/instrumented.h:112 [inline]
 atomic_fetch_sub_release include/linux/atomic/atomic-instrumented.h:400
 [inline]
 __refcount_sub_and_test include/linux/refcount.h:389 [inline]
 __refcount_dec_and_test include/linux/refcount.h:432 [inline]
 refcount_dec_and_test include/linux/refcount.h:450 [inline]
 put_dev drivers/usb/gadget/legacy/inode.c:165 [inline]
 gadgetfs_kill_sb+0x46/0x110 drivers/usb/gadget/legacy/inode.c:2104
 deactivate_locked_super+0xbc/0x130 fs/super.c:477
 cleanup_mnt+0x3d3/0x460 fs/namespace.c:1317
 task_work_run+0x1d9/0x270 kernel/task_work.c:233

The root cause is a reference count underflow in the error handling path of
gadgetfs_bind(). When gadgetfs_bind() encounters an error (e.g., memory
allocation failure), it jumps to the enomem label and calls
gadgetfs_unbind(). However, gadgetfs_unbind() is designed to tear down a
fully initialized and bound gadget, and unconditionally drops a device
reference by calling put_dev(dev). Since gadgetfs_bind() only acquires this
reference (get_dev(dev)) at the very end of the function upon complete
success, calling gadgetfs_unbind() in the error path drops a reference that
was never taken.

This leads to a premature free of the dev structure when the ep0 file is
closed, and subsequently a use-after-free when the filesystem is unmounted
and gadgetfs_kill_sb() tries to drop the initial reference.

To fix this, stop calling the full teardown function gadgetfs_unbind() from
the gadgetfs_bind() error path. Instead, manually and locally clean up only
the specific state that was successfully altered before the failure
occurred.

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=4a5c87a01894ca37f25c
Link: https://syzkaller.appspot.com/ai_job?id=d40043f8-d813-4477-b6e2-0f071c04be7c
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: 075b74841bd0065a3bda3440873c747938e69b68
-- 
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.
The person who has signed off on the patch is responsible for
addressing comments.
syzbot engineers can be reached at [email protected].
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.