mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
usb: gadget: f_tcm: fix deadlock in usbg_make_tpg()
usbg_make_tpg() held dep_lock while calling
configfs_depend_item_unlocked(), which acquires the configfs root
inode lock when operating across subsystems. This creates a circular
lock dependency with configfs_rmdir():
dep_lock -> configfs root inode lock -> su_mutex -> dep_lock
In usbg_make_tpg(), dep_lock only serialized the read of opts->ready,
which is a monotonic flag that transitions from false to true exactly
once (in tcm_set_name()) and never reverts. Remove dep_lock from
usbg_make_tpg() entirely and use READ_ONCE/WRITE_ONCE to access
opts->ready locklessly instead.
Reported-by: syzbot+c9f9d646b08f3b6032fe@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=c9f9d646b08f3b6032fe
Fixes: 4bb8548df6 ("usb: gadget: f_tcm: add configfs support")
Cc: stable@vger.kernel.org
Signed-off-by: Yun Zhou <yun.zhou@windriver.com>
Link: https://patch.msgid.link/20260731081151.285599-1-yun.zhou@windriver.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
bf1e90189a
commit
9dbf74f402
|
|
@ -1675,19 +1675,25 @@ static struct se_portal_group *usbg_make_tpg(struct se_wwn *wwn,
|
|||
|
||||
opts = container_of(tpg_instances[i].func_inst, struct f_tcm_opts,
|
||||
func_inst);
|
||||
mutex_lock(&opts->dep_lock);
|
||||
if (!opts->ready)
|
||||
goto unlock_dep;
|
||||
if (!READ_ONCE(opts->ready))
|
||||
goto unlock_inst;
|
||||
|
||||
if (opts->has_dep) {
|
||||
if (!try_module_get(opts->dependent))
|
||||
goto unlock_dep;
|
||||
goto unlock_inst;
|
||||
} else {
|
||||
/*
|
||||
* configfs_depend_item_unlocked() may acquire the configfs
|
||||
* root inode lock when the target belongs to a different
|
||||
* subsystem. Calling it under dep_lock would create a
|
||||
* circular dependency:
|
||||
* dep_lock -> configfs inode lock -> su_mutex -> dep_lock
|
||||
*/
|
||||
ret = configfs_depend_item_unlocked(
|
||||
wwn->wwn_group.cg_subsys,
|
||||
&opts->func_inst.group.cg_item);
|
||||
if (ret)
|
||||
goto unlock_dep;
|
||||
goto unlock_inst;
|
||||
}
|
||||
|
||||
tpg = kzalloc_obj(struct usbg_tpg);
|
||||
|
|
@ -1714,7 +1720,6 @@ static struct se_portal_group *usbg_make_tpg(struct se_wwn *wwn,
|
|||
|
||||
tpg_instances[i].tpg = tpg;
|
||||
tpg->fi = tpg_instances[i].func_inst;
|
||||
mutex_unlock(&opts->dep_lock);
|
||||
mutex_unlock(&tpg_instances_lock);
|
||||
return &tpg->se_tpg;
|
||||
|
||||
|
|
@ -1727,8 +1732,6 @@ static struct se_portal_group *usbg_make_tpg(struct se_wwn *wwn,
|
|||
module_put(opts->dependent);
|
||||
else
|
||||
configfs_undepend_item_unlocked(&opts->func_inst.group.cg_item);
|
||||
unlock_dep:
|
||||
mutex_unlock(&opts->dep_lock);
|
||||
unlock_inst:
|
||||
mutex_unlock(&tpg_instances_lock);
|
||||
|
||||
|
|
@ -2666,9 +2669,7 @@ static int tcm_set_name(struct usb_function_instance *f, const char *name)
|
|||
|
||||
pr_debug("tcm: Activating %s\n", name);
|
||||
|
||||
mutex_lock(&opts->dep_lock);
|
||||
opts->ready = true;
|
||||
mutex_unlock(&opts->dep_lock);
|
||||
WRITE_ONCE(opts->ready, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user