On Wed Jul 29 07:26:13 2026 +0000, Fan Wu wrote:
> audio_trigger() is deferred work (dev->wq_trigger) armed from
> snd_cx231xx_capture_trigger() on every PCM START/STOP; it dereferences
> dev->adev state and may free the URBs via cx231xx_isoc_audio_deinit().
> cx231xx_audio_fini() tore down that state without draining wq_trigger,
> so work armed before or racing fini ran against freed state.
> 
> Use disable_work_sync() in fini to drain the work and prevent further
> queueing.  Initialize the work, lock and stream_started counter at the
> top of cx231xx_audio_init(), before any fallible allocation, and clear
> the partially-built audio state on its error path, so fini is safe even
> if a later step fails.
> 
> This issue was found by an in-house static analysis tool.
> 
> Fixes: 61b04cb24a12 ("[media] cx231xx-audio: fix some locking issues")
> Cc: [email protected] # v6.10+
> Link: 
> https://lore.kernel.org/r/[email protected]
> Assisted-by: Codex:gpt-5.6
> Signed-off-by: Fan Wu <[email protected]>
> Signed-off-by: Hans Verkuil <[email protected]>

Patch committed.

Thanks,
Hans Verkuil

 drivers/media/usb/cx231xx/cx231xx-audio.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

---

diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c 
b/drivers/media/usb/cx231xx/cx231xx-audio.c
index b24ceef497e4..af04fb104cc4 100644
--- a/drivers/media/usb/cx231xx/cx231xx-audio.c
+++ b/drivers/media/usb/cx231xx/cx231xx-audio.c
@@ -581,12 +581,19 @@ static int cx231xx_audio_init(struct cx231xx *dev)
        dev_dbg(dev->dev,
                "probing for cx231xx non standard usbaudio\n");
 
+       /*
+        * Extension init errors are ignored by the cx231xx core, so fini()
+        * must be safe even if initialization fails part way through.
+        */
+       spin_lock_init(&adev->slock);
+       INIT_WORK(&dev->wq_trigger, audio_trigger);
+       atomic_set(&dev->stream_started, 0);
+
        err = snd_card_new(dev->dev, index[devnr], "Cx231xx Audio",
                           THIS_MODULE, 0, &card);
        if (err < 0)
                return err;
 
-       spin_lock_init(&adev->slock);
        err = snd_pcm_new(card, "Cx231xx Audio", 0, 0, 1, &pcm);
        if (err < 0)
                goto err_free_card;
@@ -601,8 +608,6 @@ static int cx231xx_audio_init(struct cx231xx *dev)
        strscpy(card->shortname, "Cx231xx Audio", sizeof(card->shortname));
        strscpy(card->longname, "Conexant cx231xx Audio", 
sizeof(card->longname));
 
-       INIT_WORK(&dev->wq_trigger, audio_trigger);
-
        err = snd_card_register(card);
        if (err < 0)
                goto err_free_card;
@@ -656,8 +661,10 @@ static int cx231xx_audio_init(struct cx231xx *dev)
 
 err_free_pkt_size:
        kfree(adev->alt_max_pkt_size);
+       adev->alt_max_pkt_size = NULL;
 err_free_card:
        snd_card_free(card);
+       adev->sndcard = NULL;
 
        return err;
 }
@@ -674,6 +681,8 @@ static int cx231xx_audio_fini(struct cx231xx *dev)
                return 0;
        }
 
+       disable_work_sync(&dev->wq_trigger);
+
        if (dev->adev.sndcard) {
                snd_card_free_when_closed(dev->adev.sndcard);
                kfree(dev->adev.alt_max_pkt_size);
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to