]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
most: usb: fix double free on late probe failure
authorJohan Hovold <johan@kernel.org>
Wed, 29 Oct 2025 09:30:29 +0000 (10:30 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 9 Nov 2025 02:15:20 +0000 (11:15 +0900)
The MOST subsystem has a non-standard registration function which frees
the interface on registration failures and on deregistration.

This unsurprisingly leads to bugs in the MOST drivers, and a couple of
recent changes turned a reference underflow and use-after-free in the
USB driver into several double free and a use-after-free on late probe
failures.

Fixes: 723de0f9171e ("staging: most: remove device from interface structure")
Fixes: 4b1270902609 ("most: usb: Fix use-after-free in hdm_disconnect")
Fixes: a8cc9e5fcb0e ("most: usb: hdm_probe: Fix calling put_device() before device initialization")
Cc: stable@vger.kernel.org
Cc: Christian Gromm <christian.gromm@microchip.com>
Cc: Victoria Votokina <Victoria.Votokina@kaspersky.com>
Signed-off-by: Johan Hovold <johan@kernel.org>
Link: https://patch.msgid.link/20251029093029.28922-1-johan@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/most/most_usb.c

index 10064d7b724985ab9a1a642ad4460e03633f474c..41ee169f80c551dbc90c50394c4539a4a2b21e0f 100644 (file)
@@ -1058,7 +1058,7 @@ hdm_probe(struct usb_interface *interface, const struct usb_device_id *id)
 
        ret = most_register_interface(&mdev->iface);
        if (ret)
-               goto err_free_busy_urbs;
+               return ret;
 
        mutex_lock(&mdev->io_mutex);
        if (le16_to_cpu(usb_dev->descriptor.idProduct) == USB_DEV_ID_OS81118 ||
@@ -1068,8 +1068,7 @@ hdm_probe(struct usb_interface *interface, const struct usb_device_id *id)
                if (!mdev->dci) {
                        mutex_unlock(&mdev->io_mutex);
                        most_deregister_interface(&mdev->iface);
-                       ret = -ENOMEM;
-                       goto err_free_busy_urbs;
+                       return -ENOMEM;
                }
 
                mdev->dci->dev.init_name = "dci";
@@ -1078,18 +1077,15 @@ hdm_probe(struct usb_interface *interface, const struct usb_device_id *id)
                mdev->dci->dev.release = release_dci;
                if (device_register(&mdev->dci->dev)) {
                        mutex_unlock(&mdev->io_mutex);
+                       put_device(&mdev->dci->dev);
                        most_deregister_interface(&mdev->iface);
-                       ret = -ENOMEM;
-                       goto err_free_dci;
+                       return -ENOMEM;
                }
                mdev->dci->usb_device = mdev->usb_device;
        }
        mutex_unlock(&mdev->io_mutex);
        return 0;
-err_free_dci:
-       put_device(&mdev->dci->dev);
-err_free_busy_urbs:
-       kfree(mdev->busy_urbs);
+
 err_free_ep_address:
        kfree(mdev->ep_address);
 err_free_cap: