--- /dev/null
+From 5f0b5f4d50fa0faa8c76ef9d42a42e8d43f98b44 Mon Sep 17 00:00:00 2001
+From: Schspa Shi <schspa@gmail.com>
+Date: Sun, 8 May 2022 23:02:47 +0800
+Subject: usb: gadget: fix race when gadget driver register via ioctl
+
+From: Schspa Shi <schspa@gmail.com>
+
+commit 5f0b5f4d50fa0faa8c76ef9d42a42e8d43f98b44 upstream.
+
+The usb_gadget_register_driver can be called multi time by to
+threads via USB_RAW_IOCTL_RUN ioctl syscall, which will lead
+to multiple registrations.
+
+Call trace:
+ driver_register+0x220/0x3a0 drivers/base/driver.c:171
+ usb_gadget_register_driver_owner+0xfb/0x1e0
+ drivers/usb/gadget/udc/core.c:1546
+ raw_ioctl_run drivers/usb/gadget/legacy/raw_gadget.c:513 [inline]
+ raw_ioctl+0x1883/0x2730 drivers/usb/gadget/legacy/raw_gadget.c:1220
+ ioctl USB_RAW_IOCTL_RUN
+
+This routine allows two processes to register the same driver instance
+via ioctl syscall. which lead to a race condition.
+
+Please refer to the following scenarios.
+
+ T1 T2
+------------------------------------------------------------------
+usb_gadget_register_driver_owner
+ driver_register driver_register
+ driver_find driver_find
+ bus_add_driver bus_add_driver
+ priv alloced <context switch>
+ drv->p = priv;
+ <schedule out>
+ kobject_init_and_add // refcount = 1;
+ //couldn't find an available UDC or it's busy
+ <context switch>
+ priv alloced
+ drv->priv = priv;
+ kobject_init_and_add
+ ---> refcount = 1 <------
+ // register success
+ <context switch>
+===================== another ioctl/process ======================
+ driver_register
+ driver_find
+ k = kset_find_obj()
+ ---> refcount = 2 <------
+ <context out>
+ driver_unregister
+ // drv->p become T2's priv
+ ---> refcount = 1 <------
+ <context switch>
+ kobject_put(k)
+ ---> refcount = 0 <------
+ return priv->driver;
+ --------UAF here----------
+
+There will be UAF in this scenario.
+
+We can fix it by adding a new STATE_DEV_REGISTERING device state to
+avoid double register.
+
+Reported-by: syzbot+dc7c3ca638e773db07f6@syzkaller.appspotmail.com
+Link: https://lore.kernel.org/all/000000000000e66c2805de55b15a@google.com/
+Reviewed-by: Andrey Konovalov <andreyknvl@gmail.com>
+Signed-off-by: Schspa Shi <schspa@gmail.com>
+Link: https://lore.kernel.org/r/20220508150247.38204-1-schspa@gmail.com
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/gadget/legacy/raw_gadget.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/usb/gadget/legacy/raw_gadget.c
++++ b/drivers/usb/gadget/legacy/raw_gadget.c
+@@ -144,6 +144,7 @@ enum dev_state {
+ STATE_DEV_INVALID = 0,
+ STATE_DEV_OPENED,
+ STATE_DEV_INITIALIZED,
++ STATE_DEV_REGISTERING,
+ STATE_DEV_RUNNING,
+ STATE_DEV_CLOSED,
+ STATE_DEV_FAILED
+@@ -507,6 +508,7 @@ static int raw_ioctl_run(struct raw_dev
+ ret = -EINVAL;
+ goto out_unlock;
+ }
++ dev->state = STATE_DEV_REGISTERING;
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ ret = usb_gadget_probe_driver(&dev->driver);