summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohan Hovold <johan@kernel.org>2026-03-27 13:43:04 +0300
committerMark Brown <broonie@kernel.org>2026-04-01 20:21:09 +0300
commitb99e3ddb91b499d920e63a2daff8880be68cfe9e (patch)
treead951e031c431d7b02b6834a434d7365892807e1
parent762a3847a05c5c229009d36fbd0e2feee9dff81a (diff)
downloadlinux-b99e3ddb91b499d920e63a2daff8880be68cfe9e.tar.xz
spi: ch341: fix memory leaks on probe failures
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>
-rw-r--r--drivers/spi/spi-ch341.c36
1 files changed, 25 insertions, 11 deletions
diff --git a/drivers/spi/spi-ch341.c b/drivers/spi/spi-ch341.c
index 79d2f9ab4ef0..ded093566260 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);
}