summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPei Xiao <xiaopei01@kylinos.cn>2026-08-04 14:47:01 +0800
committerHans Verkuil <hverkuil+cisco@kernel.org>2026-09-08 15:10:03 +0200
commit75016a992d9b03f5cc6df1414d1da35840d4feeb (patch)
treed5a665442196227fbf46cd6c4603324fc9ad22d5
parent6802ad4b6b267dda02209b5811edac7825c8a5f6 (diff)
downloadlinux-next-75016a992d9b03f5cc6df1414d1da35840d4feeb.tar.gz
linux-next-75016a992d9b03f5cc6df1414d1da35840d4feeb.zip
media: cx23885: Fix use-after-free in cx23885_finidev due to race condition
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: stable@vger.kernel.org Assisted-by: Codex:deepseek-v4-flash Signed-off-by: Pei Xiao <xiaopei01@kylinos.cn> Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
-rw-r--r--drivers/media/pci/cx23885/cx23885-core.c4
1 files changed, 4 insertions, 0 deletions
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);