From: Hui Peng <benquike@gmail.com>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org,
Hui Peng <benquike@gmail.com>
Subject: [PATCH] usb: gadget: f_tcm: detach the gadget in usbg_drop_tpg() to fix a use-after-free
Date: Sat, 19 Sep 2026 09:07:26 +0000 [thread overview]
Message-ID: <20260919090726.3256229-1-benquike@gmail.com> (raw)
A target portal group can be removed with rmdir() on its configfs
directory while it is still enabled and still attached to a USB gadget
function. usbg_drop_tpg() frees the struct usbg_tpg but never calls
usbg_detach(), and it leaves opts->can_attach set, so the function
instance keeps a dangling tpg pointer and a subsequent bind to a UDC
happily attaches to freed memory.
Enumerating the gadget then dereferences the freed tpg from the UAS/BOT
completion path, in softirq context:
==================================================================
BUG: KASAN: slab-use-after-free in usbg_submit_command.isra.0+0xbe7/0xd50
Read of size 8 at addr ffff888107493478 by task swapper/3/0
CPU: 3 UID: 0 PID: 0 Comm: swapper/3 Tainted: G B D 7.3.0-rc3-g5dd1818b15d9 #1 PREEMPT(lazy)
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996)
Call Trace:
<IRQ>
dump_stack_lvl+0x70/0xa0
print_report+0x153/0x4c6
kasan_report+0xf1/0x120
usbg_submit_command.isra.0+0xbe7/0xd50
uasp_cmd_complete+0x83/0xf0
dummy_timer+0x1337/0x2d60
__hrtimer_run_queues+0x2a3/0x640
hrtimer_run_softirq+0x1b1/0x3d0
handle_softirqs+0x188/0x4e0
__irq_exit_rcu+0x62/0x150
sysvec_apic_timer_interrupt+0x6b/0x80
</IRQ>
Allocated by task 1:
__kmalloc_cache_noprof+0x16a/0x380
usbg_make_tpg+0x243/0x580
target_fabric_make_tpg+0xb1/0x7f0
configfs_mkdir+0x4e9/0xe10
vfs_mkdir+0x2ed/0x790
__x64_sys_mkdir+0x6f/0xa0
Freed by task 1:
kfree+0x159/0x420
config_item_cleanup+0x148/0x1e0
config_item_put+0x90/0xb0
configfs_rmdir+0x816/0xa50
==================================================================
Detach the gadget in usbg_drop_tpg() if the tpg is still connected, and
clear opts->can_attach for every function instance bound to this tpg so
that a later usbg_attach() cannot pick up the freed object.
The forward declarations of usbg_attach() and usbg_detach() are moved
above usbg_drop_tpg() since it now calls usbg_detach().
Assisted-by: LLM
Signed-off-by: Hui Peng <benquike@gmail.com>
---
No Fixes: tag: I could not identify a single commit that introduced
the problem with confidence, so I have left it out rather than guess.
Reproduced on Linux 7.3.0-rc3 (5dd1818b15d9) with KASAN under QEMU using
dummy_hcd: create a tcm function and a target tpgt_1, write 1 to its
"enable" attribute, link the function into a gadget config, rmdir tpgt_1
without disabling it first, then bind the gadget to dummy_udc.0. With
this patch applied the same sequence produces no KASAN splat.
drivers/usb/gadget/function/f_tcm.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
--- a/drivers/usb/gadget/function/f_tcm.c
+++ b/drivers/usb/gadget/function/f_tcm.c
@@ -1756,6 +1756,9 @@ unlock_inst:
static int tcm_usbg_drop_nexus(struct usbg_tpg *);
+static int usbg_attach(struct usbg_tpg *);
+static void usbg_detach(struct usbg_tpg *);
+
static void usbg_drop_tpg(struct se_portal_group *se_tpg)
{
struct usbg_tpg *tpg = container_of(se_tpg,
@@ -1763,6 +1766,11 @@ static void usbg_drop_tpg(struct se_port
unsigned i;
struct f_tcm_opts *opts;
+ if (tpg->gadget_connect) {
+ usbg_detach(tpg);
+ tpg->gadget_connect = false;
+ }
+
tcm_usbg_drop_nexus(tpg);
core_tpg_deregister(se_tpg);
destroy_workqueue(tpg->workqueue);
@@ -1776,6 +1784,7 @@ static void usbg_drop_tpg(struct se_port
opts = container_of(tpg_instances[i].func_inst,
struct f_tcm_opts, func_inst);
mutex_lock(&opts->dep_lock);
+ opts->can_attach = false;
if (opts->has_dep)
module_put(opts->dependent);
else
@@ -1832,9 +1841,6 @@ static struct configfs_attribute *usbg_w
NULL,
};
-static int usbg_attach(struct usbg_tpg *);
-static void usbg_detach(struct usbg_tpg *);
-
static int usbg_enable_tpg(struct se_portal_group *se_tpg, bool enable)
{
struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
--
2.43.0
next reply other threads:[~2026-09-19 9:07 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-19 9:07 Hui Peng [this message]
2026-09-19 11:28 ` [PATCH v2] usb: gadget: f_tcm: detach the gadget in usbg_drop_tpg() to fix a use-after-free Hui Peng
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260919090726.3256229-1-benquike@gmail.com \
--to=benquike@gmail.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.