From: sashiko-bot@kernel.org
To: "Óscar Megía López" <megia.oscar@gmail.com>
Cc: "Eugenio Perez" <eperezma@redhat.com>,
virtualization@lists.linux.dev,
"Michael S. Tsirkin" <mst@redhat.com>
Subject: Re: [PATCH v5] drm/qxl: fix use-after-free in qxl_irq_handler on PCI
Date: Fri, 02 Oct 2026 09:13:06 +0000 [thread overview]
Message-ID: <20261002091307.384651F0089C@smtp.kernel.org> (raw)
In-Reply-To: <20261001184321.80615-1-megia.oscar@gmail.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] drm/qxl: use-after-free on qdev in client_monitors_config_work
- [High] drm/qxl: IRQ storm on shared interrupt line due to race
- [Medium] drm/qxl: guaranteed 1-second timeout delay on device unbind
--
commit 4e30a9d9b42421b43ae1402ef7242873b17ea62b
Author: Óscar Megía López <megia.oscar@gmail.com>
drm/qxl: fix use-after-free in qxl_irq_handler on PCI
This commit aims to fix a slab-use-after-free in the qxl_irq_handler during
unbind. It masks interrupts on the QXL hardware and reorders the IRQ cleanup
logic to be handled in qxl_pci_remove() before legacy VGA resources are
released.
> diff --git a/drivers/gpu/drm/qxl/qxl_drv.c b/drivers/gpu/drm/qxl/qxl_drv.c
> --- a/drivers/gpu/drm/qxl/qxl_drv.c
> +++ b/drivers/gpu/drm/qxl/qxl_drv.c
> @@ -159,10 +159,12 @@ static void
> qxl_pci_remove(struct pci_dev *pdev)
> {
> struct drm_device *dev = pci_get_drvdata(pdev);
> + struct qxl_device *qdev = to_qxl(dev);
>
> drm_kms_helper_poll_fini(dev);
> drm_dev_unregister(dev);
> drm_atomic_helper_shutdown(dev);
> + qxl_irq_fini(qdev);
[Severity: Medium]
Does placing qxl_irq_fini() here cause a guaranteed timeout during unbind?
Later in the teardown process, the DRM release callback qxl_drm_release()
calls qxl_device_fini(), which invokes qxl_io_notify_oom() and waits for
the hardware to signal completion via an interrupt:
drivers/gpu/drm/qxl/qxl_kms.c:qxl_device_fini() {
...
qxl_io_notify_oom(qdev);
wait_event_timeout(qdev->release_event,
atomic_read(&qdev->release_count) == 0,
HZ);
...
}
Since the interrupt handler is permanently unregistered at this point,
the interrupt is never processed. Will wait_event_timeout() unconditionally
hit its 1-second timeout on every unbind?
> if (pci_is_vga(pdev) && pdev->revision < 5)
> vga_put(pdev, VGA_RSRC_LEGACY_IO);
> }
[ ... ]
> diff --git a/drivers/gpu/drm/qxl/qxl_irq.c b/drivers/gpu/drm/qxl/qxl_irq.c
> --- a/drivers/gpu/drm/qxl/qxl_irq.c
> +++ b/drivers/gpu/drm/qxl/qxl_irq.c
> @@ -105,3 +105,16 @@ int qxl_irq_init(struct qxl_device *qdev)
> }
> return 0;
> }
> +
> +void qxl_irq_fini(struct qxl_device *qdev)
> +{
> + struct drm_device *ddev = &qdev->ddev;
> + struct pci_dev *pdev = to_pci_dev(ddev->dev);
> +
> + if (qdev->ram_header)
> + qdev->ram_header->int_mask = 0;
[Severity: High]
Can this race with the interrupt handler and cause an IRQ storm?
While this clears the interrupt mask, it does not notify the hardware via an
I/O update. If an interrupt arrives right before this, qxl_irq_handler()
runs concurrently:
drivers/gpu/drm/qxl/qxl_irq.c:qxl_irq_handler() {
...
qdev->ram_header->int_mask = QXL_INTERRUPT_MASK;
outb(0, qdev->io_base + QXL_IO_UPDATE_IRQ);
...
}
The handler will unconditionally set the mask back to QXL_INTERRUPT_MASK
and re-enable interrupts at the hardware level.
When free_irq() subsequently removes the handler, could the hardware be left
actively asserting interrupts on a shared PCI line with no handler registered
to clear them, potentially breaking other devices on the same line?
> +
> + cancel_work_sync(&qdev->client_monitors_config_work);
[Severity: High]
Does cancelling the work before freeing the IRQ create a race condition that
leads to a use-after-free?
Because the IRQ handler is still active when cancel_work_sync() is called,
an arriving interrupt can trigger qxl_irq_handler() which schedules the work
again:
drivers/gpu/drm/qxl/qxl_irq.c:qxl_irq_handler() {
...
if (pending & QXL_INTERRUPT_CLIENT_MONITORS_CONFIG) {
schedule_work(&qdev->client_monitors_config_work);
}
...
}
If the work is re-queued after cancel_work_sync() returns, qdev will
eventually be freed via devres during device removal. When the workqueue
later processes the dangling work item, will it access the freed memory?
> +
> + free_irq(pdev->irq, ddev);
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261001184321.80615-1-megia.oscar@gmail.com?part=1
prev parent reply other threads:[~2026-10-02 9:13 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-01 18:43 [PATCH v5] drm/qxl: fix use-after-free in qxl_irq_handler on PCI Óscar Megía López
2026-10-02 9:13 ` sashiko-bot [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261002091307.384651F0089C@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=eperezma@redhat.com \
--cc=megia.oscar@gmail.com \
--cc=mst@redhat.com \
--cc=sashiko-reviews@lists.linux.dev \
--cc=virtualization@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox