[PATCH 1/2] spi: ch341: fix memory leaks on probe failures
From: Johan Hovold
Date: Fri Mar 27 2026 - 06:49:44 EST
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@xxxxxxxxxxxxxxx # 6.11
Cc: Johannes Thumshirn <jth@xxxxxxxxxx>
Signed-off-by: Johan Hovold <johan@xxxxxxxxxx>
---
drivers/spi/spi-ch341.c | 36 +++++++++++++++++++++++++-----------
1 file changed, 25 insertions(+), 11 deletions(-)
diff --git a/drivers/spi/spi-ch341.c b/drivers/spi/spi-ch341.c
index 2fdb1c020339..ea92ba986201 100644
--- a/drivers/spi/spi-ch341.c
+++ b/drivers/spi/spi-ch341.c
@@ -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);
}
--
2.52.0