On Tue Aug 4 14:47:01 2026 +0800, Pei Xiao wrote:
> In cx23885_v4l2_dev_notify_init, &dev->cx25840_work is bound with
> cx23885_av_work_handler, and &dev->ir_rx_work and &dev->ir_tx_work
> are bound with cx23885_ir_rx_work_handler and
> cx23885_ir_tx_work_handler. cx23885_irq can schedule these works on
> system_wq when an AV_CORE interrupt is received, and the IR subdevice
> can also schedule the IR works from its interrupt service routine via
> the v4l2_device notify callback.
> 
> If we remove the device, cx23885_finidev makes cleanup and the memory
> allocated for dev is released by kfree(dev), while the works mentioned
> above may still be pending or running. The sequence of operations that
> may lead to a UAF bug is as follows:
> 
> CPU0                                      CPU1
> 
>                                           | cx23885_irq
>                                           | schedule_work(&dev->cx25840_work)
> cx23885_finidev                           |
> cx23885_input_fini(dev)                   |
> cx23885_ir_fini(dev)                      |
> cx23885_shutdown(dev)                     |
> free_irq(pci_dev->irq, dev)               |
> pci_disable_device(pci_dev)               |
> cx23885_dev_unregister(dev)               |
> v4l2_device_unregister(v4l2_dev)          |
> kfree(dev)                                |
> // dev is freed                           |
>                                           | cx23885_av_work_handler
>                                           | // use dev (use-after-free)
> 
> Fix it by canceling the works after the IRQ handler that can schedule
> them has been stopped, and before proceeding with the remaining
> cleanup in cx23885_finidev.
> 
> Note that the flush_work() calls in cx23885_input_ir_stop() do not
> close this race: they only wait for works that are already queued or
> running at that moment, they do not prevent the IRQ handler, which is
> still registered at that point, from scheduling the works again
> afterwards, and they are skipped entirely when dev->sd_ir is NULL.
> The cancel_work_sync() calls are therefore placed after free_irq(),
> the only point at which no new work can be scheduled.
> 
> Fixes: e5514f104d87 ("V4L/DVB: cx23885: Move AV Core irq handling to a work 
> handler")
> Cc: [email protected]
> Assisted-by: Codex:deepseek-v4-flash
> Signed-off-by: Pei Xiao <[email protected]>
> Signed-off-by: Hans Verkuil <[email protected]>

Patch committed.

Thanks,
Hans Verkuil

 drivers/media/pci/cx23885/cx23885-core.c | 4 ++++
 1 file changed, 4 insertions(+)

---

diff --git a/drivers/media/pci/cx23885/cx23885-core.c 
b/drivers/media/pci/cx23885/cx23885-core.c
index 5fb26285e4af..7498091176b7 100644
--- a/drivers/media/pci/cx23885/cx23885-core.c
+++ b/drivers/media/pci/cx23885/cx23885-core.c
@@ -2246,6 +2246,10 @@ static void cx23885_finidev(struct pci_dev *pci_dev)
        /* unregister stuff */
        free_irq(pci_dev->irq, dev);
 
+       cancel_work_sync(&dev->cx25840_work);
+       cancel_work_sync(&dev->ir_rx_work);
+       cancel_work_sync(&dev->ir_tx_work);
+
        pci_disable_device(pci_dev);
 
        cx23885_dev_unregister(dev);
_______________________________________________
linuxtv-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to