On Fri Aug 14 21:41:00 2026 +0800, Ruoyu Wang wrote:
> 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")
> Cc: [email protected]
> Signed-off-by: Ruoyu Wang <[email protected]>
> Signed-off-by: Hans Verkuil <[email protected]>

Patch committed.

Thanks,
Hans Verkuil

 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 d3fff47f0edf..601a12e122f1 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)
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to