]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
spi: ch341: fix memory leaks on probe failures
authorJohan Hovold <johan@kernel.org>
Fri, 27 Mar 2026 10:43:04 +0000 (11:43 +0100)
committerMark Brown <broonie@kernel.org>
Wed, 1 Apr 2026 17:21:09 +0000 (18:21 +0100)
Make sure to deregister the controller, disable pins, and kill and free
the RX URB on probe failures to mirror disconnect and avoid memory
leaks and use-after-free.

Also add an explicit URB kill on disconnect for symmetry (even if that
is not strictly required as USB core would have stopped it in the
current setup).

Fixes: 8846739f52af ("spi: add ch341a usb2spi driver")
Cc: stable@vger.kernel.org # 6.11
Cc: Johannes Thumshirn <jth@kernel.org>
Signed-off-by: Johan Hovold <johan@kernel.org>
Link: https://patch.msgid.link/20260327104305.1309915-2-johan@kernel.org
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi-ch341.c

index 79d2f9ab4ef037a393d4d9c7e641047cfaf9f67c..ded093566260585ea57ca528f110b6fb73fc36ae 100644 (file)
@@ -173,17 +173,17 @@ static int ch341_probe(struct usb_interface *intf,
 
        ch341->tx_buf =
                devm_kzalloc(&udev->dev, CH341_PACKET_LENGTH, GFP_KERNEL);
-       if (!ch341->tx_buf)
-               return -ENOMEM;
+       if (!ch341->tx_buf) {
+               ret = -ENOMEM;
+               goto err_free_urb;
+       }
 
        usb_fill_bulk_urb(ch341->rx_urb, udev, ch341->read_pipe, ch341->rx_buf,
                          ch341->rx_len, ch341_recv, ch341);
 
        ret = usb_submit_urb(ch341->rx_urb, GFP_KERNEL);
-       if (ret) {
-               usb_free_urb(ch341->rx_urb);
-               return -ENOMEM;
-       }
+       if (ret)
+               goto err_free_urb;
 
        ctrl->bus_num = -1;
        ctrl->mode_bits = SPI_CPHA;
@@ -195,21 +195,34 @@ static int ch341_probe(struct usb_interface *intf,
 
        ret = ch341_config_stream(ch341);
        if (ret)
-               return ret;
+               goto err_kill_urb;
 
        ret = ch341_enable_pins(ch341, true);
        if (ret)
-               return ret;
+               goto err_kill_urb;
 
        ret = spi_register_controller(ctrl);
        if (ret)
-               return ret;
+               goto err_disable_pins;
 
        ch341->spidev = spi_new_device(ctrl, &chip);
-       if (!ch341->spidev)
-               return -ENOMEM;
+       if (!ch341->spidev) {
+               ret = -ENOMEM;
+               goto err_unregister;
+       }
 
        return 0;
+
+err_unregister:
+       spi_unregister_controller(ctrl);
+err_disable_pins:
+       ch341_enable_pins(ch341, false);
+err_kill_urb:
+       usb_kill_urb(ch341->rx_urb);
+err_free_urb:
+       usb_free_urb(ch341->rx_urb);
+
+       return ret;
 }
 
 static void ch341_disconnect(struct usb_interface *intf)
@@ -219,6 +232,7 @@ static void ch341_disconnect(struct usb_interface *intf)
        spi_unregister_device(ch341->spidev);
        spi_unregister_controller(ch341->ctrl);
        ch341_enable_pins(ch341, false);
+       usb_kill_urb(ch341->rx_urb);
        usb_free_urb(ch341->rx_urb);
 }