drivers/media/usb/au0828/au0828-dvb.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-)
start_urb_transfer() stores each allocated URB in dev->urbs[], but sets
urb_streaming only after all URBs have been submitted. If a later URB or
transfer buffer allocation fails, earlier entries are left allocated. A
submission failure calls stop_urb_transfer(), but that function returns
immediately while urb_streaming is false, leaving both submitted and
unsubmitted URBs behind.
Make stop_urb_transfer() release every populated slot regardless of the
streaming flag and clear each slot after release. Route all start errors
through this cleanup. usb_kill_urb() safely handles both submitted and
unsubmitted URBs, while the existing preallocation check preserves the
lifetime of shared transfer buffers.
This issue was found by a static analysis checker and confirmed by
manual source review.
Fixes: 265a6510629a ("V4L/DVB (7621): Add support for Hauppauge HVR950Q/HVR850/FusioHDTV7-USB")
Signed-off-by: Ruoyu Wang <ruoyuw560@gmail.com>
---
drivers/media/usb/au0828/au0828-dvb.c | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c
index 31123e6f9fc31..aecc133ea11bb 100644
--- a/drivers/media/usb/au0828/au0828-dvb.c
+++ b/drivers/media/usb/au0828/au0828-dvb.c
@@ -163,9 +163,6 @@ static int stop_urb_transfer(struct au0828_dev *dev)
dprintk(2, "%s()\n", __func__);
- if (!dev->urb_streaming)
- return 0;
-
if (dev->bulk_timeout_running == 1) {
dev->bulk_timeout_running = 0;
timer_delete(&dev->bulk_timeout);
@@ -179,6 +176,7 @@ static int stop_urb_transfer(struct au0828_dev *dev)
kfree(dev->urbs[i]->transfer_buffer);
usb_free_urb(dev->urbs[i]);
+ dev->urbs[i] = NULL;
}
}
@@ -200,8 +198,10 @@ static int start_urb_transfer(struct au0828_dev *dev)
for (i = 0; i < URB_COUNT; i++) {
dev->urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
- if (!dev->urbs[i])
- return -ENOMEM;
+ if (!dev->urbs[i]) {
+ ret = -ENOMEM;
+ goto err;
+ }
purb = dev->urbs[i];
@@ -217,7 +217,7 @@ static int start_urb_transfer(struct au0828_dev *dev)
ret = -ENOMEM;
pr_err("%s: failed big buffer allocation, err = %d\n",
__func__, ret);
- return ret;
+ goto err;
}
purb->status = -EINPROGRESS;
@@ -235,10 +235,9 @@ static int start_urb_transfer(struct au0828_dev *dev)
for (i = 0; i < URB_COUNT; i++) {
ret = usb_submit_urb(dev->urbs[i], GFP_ATOMIC);
if (ret != 0) {
- stop_urb_transfer(dev);
pr_err("%s: failed urb submission, err = %d\n",
__func__, ret);
- return ret;
+ goto err;
}
}
@@ -249,6 +248,10 @@ static int start_urb_transfer(struct au0828_dev *dev)
dev->bulk_timeout_running = 1;
return 0;
+
+err:
+ stop_urb_transfer(dev);
+ return ret;
}
static void au0828_start_transport(struct au0828_dev *dev)
--
2.51.0
© 2016 - 2026 Red Hat, Inc.