
From: Uttkarsh Aggarwal <quic_uaggarwa@quicinc.com> stable inclusion from stable-v4.19.285 commit 9a95fba9362a161127673e29243ca5cfea48defe category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/IBWVWG CVE: CVE-2022-49755 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- commit efb6b535207395a5c7317993602e2503ca8cb4b3 upstream. While exercising the unbind path, with the current implementation the functionfs_unbind would be calling which waits for the ffs->mutex to be available, however within the same time ffs_ep0_read is invoked & if no setup packets are pending, it will invoke function wait_event_interruptible_exclusive_locked_irq which by definition waits for the ev.count to be increased inside the same mutex for which functionfs_unbind is waiting. This creates deadlock situation because the functionfs_unbind won't get the lock until ev.count is increased which can only happen if the caller ffs_func_unbind can proceed further. Following is the illustration: CPU1 CPU2 ffs_func_unbind() ffs_ep0_read() mutex_lock(ffs->mutex) wait_event(ffs->ev.count) functionfs_unbind() mutex_lock(ffs->mutex) mutex_unlock(ffs->mutex) ffs_event_add() <deadlock> Fix this by moving the event unbind before functionfs_unbind to ensure the ev.count is incrased properly. Fixes: 6a19da111057 ("usb: gadget: f_fs: Prevent race during ffs_ep0_queue_wait") Cc: stable <stable@kernel.org> Signed-off-by: Uttkarsh Aggarwal <quic_uaggarwa@quicinc.com> Link: https://lore.kernel.org/r/20230525092854.7992-1-quic_uaggarwa@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Conflicts: drivers/usb/gadget/function/f_fs.c [context conflict] Signed-off-by: Guo Mengqi <guomengqi3@huawei.com> --- drivers/usb/gadget/function/f_fs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 7cb32257307b..04b2d6ca9d43 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -3500,6 +3500,7 @@ static void ffs_func_unbind(struct usb_configuration *c, ffs->func = NULL; } + ffs_event_add(ffs, FUNCTIONFS_UNBIND); if (!--opts->refcnt) functionfs_unbind(ffs); @@ -3522,8 +3523,6 @@ static void ffs_func_unbind(struct usb_configuration *c, func->function.hs_descriptors = NULL; func->function.ss_descriptors = NULL; func->interfaces_nums = NULL; - - ffs_event_add(ffs, FUNCTIONFS_UNBIND); } static struct usb_function *ffs_alloc(struct usb_function_instance *fi) -- 2.22.0