]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.15-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 18 May 2022 12:45:05 +0000 (14:45 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 18 May 2022 12:45:05 +0000 (14:45 +0200)
added patches:
usb-gadget-fix-race-when-gadget-driver-register-via-ioctl.patch

queue-5.15/usb-gadget-fix-race-when-gadget-driver-register-via-ioctl.patch [new file with mode: 0644]

diff --git a/queue-5.15/usb-gadget-fix-race-when-gadget-driver-register-via-ioctl.patch b/queue-5.15/usb-gadget-fix-race-when-gadget-driver-register-via-ioctl.patch
new file mode 100644 (file)
index 0000000..6d5645c
--- /dev/null
@@ -0,0 +1,92 @@
+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
+@@ -145,6 +145,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
+@@ -508,6 +509,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);