From: Nicolin Chen <nicolinc@nvidia.com>
To: <will@kernel.org>, <robin.murphy@arm.com>, <jgg@nvidia.com>,
"Jonathan Cameron" <jonathan.cameron@oss.qualcomm.com>
Cc: <joro@8bytes.org>, <bhelgaas@google.com>, <praan@google.com>,
<kevin.tian@intel.com>, <kees@kernel.org>, <smostafa@google.com>,
<baolu.lu@linux.intel.com>,
Jean-Philippe Brucker <jpb@kernel.org>,
"Eric Auger" <eric.auger@redhat.com>,
<linux-arm-kernel@lists.infradead.org>, <iommu@lists.linux.dev>,
<linux-kernel@vger.kernel.org>, <linux-pci@vger.kernel.org>,
<skaestle@nvidia.com>, <mmarrid@nvidia.com>,
<skolothumtho@nvidia.com>, <bbiber@nvidia.com>,
<harsha.v@oss.qualcomm.com>
Subject: [PATCH v4 05/15] iommu/arm-smmu-v3: Flush in-flight fault work on domain detach
Date: Thu, 10 Sep 2026 16:16:57 -0700 [thread overview]
Message-ID: <848cb4c8a79da1f434966d998be0f4ebddf80fb7.1789081084.git.nicolinc@nvidia.com> (raw)
In-Reply-To: <cover.1789081084.git.nicolinc@nvidia.com>
After the hardware queue is drained, an event may still be moving from the
IRQ thread to the IOPF workqueue, while earlier IOPF work is still running.
Synchronize the EVTQ and combined IRQs, then call iopf_queue_flush_dev().
This finishes all old-domain work before the IOMMU core frees the domain.
Skip synchronize_irq() after a drain timeout because a stuck consumer can
otherwise leave it waiting forever.
If arm_smmu_wait_for_queue_drained() times out, fault work may still be in
flight, and iopf_queue_remove_device() would free iopf groups that the work
also references. Skip the iopf teardown and leak the master_domain, rather
than risk a use-after-free.
The skip also leaks the iopf refcount, keeping the device enrolled on the
IOPF queue, which would strand its fault parameter on the queue list once
the device teardown frees dev->iommu, crashing a later iopf_queue_free().
Reclaim the enrollment in arm_smmu_release_device(), where all the attach
handles are gone so a straggler report cannot queue a new fault group.
Note that a residual race window remains between an iopf_queue_flush_dev()
and iopf_queue_remove_device(): a fault arriving in between still resolves
to the old attach handle, as the IOMMU core publishes a handle change only
after the driver ops return. This window predates the drain narrowing it,
and is only closable by an ordering fix in the IOMMU core. Furthermore, a
timed-out drain shares exactly the same window, given that it must keep the
device enrolled on the IOPF queue, where iopf_queue_remove_device() would
free the iopf groups that any in-flight fault work still references.
Fixes: cfea71aea921 ("iommu/arm-smmu-v3: Put iopf enablement in the domain attach path")
Cc: stable@vger.kernel.org # v6.16
Co-developed-by: Barak Biber <bbiber@nvidia.com>
Signed-off-by: Barak Biber <bbiber@nvidia.com>
Co-developed-by: Stefan Kaestle <skaestle@nvidia.com>
Signed-off-by: Stefan Kaestle <skaestle@nvidia.com>
Signed-off-by: Malak Marrid <mmarrid@nvidia.com>
Assisted-by: Claude:claude-fable-5
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
---
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 46 +++++++++++++++++++--
1 file changed, 43 insertions(+), 3 deletions(-)
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index ef1fddad7868e..a915d8b0baf69 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -3402,6 +3402,7 @@ void arm_smmu_attach_release(struct arm_smmu_attach_state *state)
struct arm_smmu_master_domain *master_domain = state->old_master_domain;
struct arm_smmu_master *master = state->master;
struct arm_smmu_device *smmu = master->smmu;
+ bool timed_out = false;
lockdep_assert_not_held(&arm_smmu_asid_lock);
iommu_group_mutex_assert(master->dev);
@@ -3414,8 +3415,38 @@ void arm_smmu_attach_release(struct arm_smmu_attach_state *state)
* which the IOMMU core might free once this returns. Drain the hardware
* eventq, so that a pending event cannot turn into new fault work.
*/
- if (master_domain->using_iopf && master->stall_enabled)
- arm_smmu_wait_for_queue_drained(smmu, &smmu->evtq.q, false);
+ if (master_domain->using_iopf && master->stall_enabled) {
+ timed_out = arm_smmu_wait_for_queue_drained(smmu, &smmu->evtq.q,
+ false);
+ /*
+ * Ensure pending events have reached the IOPF queue, unless
+ * the drain timed out: a stuck consumer would also block an
+ * unbounded wait_event() inside the synchronize_irq().
+ */
+ if (!timed_out) {
+ if (smmu->evtq.q.irq)
+ synchronize_irq(smmu->evtq.q.irq);
+ /* Pending events might be in the combined_irq handler */
+ if (smmu->combined_irq)
+ synchronize_irq(smmu->combined_irq);
+ }
+ }
+
+ /* Lastly, flush the fault work that the drained events queued */
+ if (master_domain->using_iopf) {
+ iopf_queue_flush_dev(master->dev);
+
+ /*
+ * A timed-out drain may leave fault work in flight, and
+ * iopf_queue_remove_device() would free iopf groups that
+ * such work still references. Skip the iopf teardown and
+ * leak master_domain, rather than risk a UAF.
+ */
+ if (WARN_ON(timed_out)) {
+ state->old_master_domain = NULL;
+ return;
+ }
+ }
arm_smmu_disable_iopf(master, master_domain);
kfree(master_domain);
@@ -4399,7 +4430,16 @@ static void arm_smmu_release_device(struct device *dev)
{
struct arm_smmu_master *master = dev_iommu_priv_get(dev);
- WARN_ON(master->iopf_refcount);
+ /*
+ * A timed-out drain in arm_smmu_attach_release() leaks the refcount,
+ * keeping the device on the IOPF queue. Reclaim it here, since every
+ * attach handle is gone: a straggler fault can no longer queue a new
+ * fault group, so the queue turns stable once flushed.
+ */
+ if (WARN_ON(master->iopf_refcount)) {
+ iopf_queue_flush_dev(dev);
+ iopf_queue_remove_device(master->smmu->evtq.iopf, dev);
+ }
arm_smmu_disable_pasid(master);
arm_smmu_remove_master(master);
--
2.43.0
next prev parent reply other threads:[~2026-09-10 23:17 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-10 23:16 [PATCH v4 00/15] iommu/arm-smmu-v3: Add PRI support Nicolin Chen
2026-09-10 23:16 ` [PATCH v4 01/15] iommu/arm-smmu-v3: Disable the impl before disabling the SMMU on shutdown Nicolin Chen
2026-09-10 23:32 ` sashiko-bot
2026-09-11 0:14 ` Jonathan Cameron
2026-09-11 23:17 ` Nicolin Chen
2026-09-10 23:16 ` [PATCH v4 02/15] iommu/arm-smmu-v3: Add arm_smmu_attach_release() Nicolin Chen
2026-09-10 23:28 ` sashiko-bot
2026-09-11 0:14 ` Jonathan Cameron
2026-09-10 23:16 ` [PATCH v4 03/15] iommu/arm-smmu-v3: Add Q_POS() macro Nicolin Chen
2026-09-10 23:21 ` sashiko-bot
2026-09-10 23:16 ` [PATCH v4 04/15] iommu/arm-smmu-v3: Drain in-flight fault events on domain detach Nicolin Chen
2026-09-10 23:31 ` sashiko-bot
2026-09-11 0:14 ` Jonathan Cameron
2026-09-10 23:16 ` Nicolin Chen [this message]
2026-09-10 23:35 ` [PATCH v4 05/15] iommu/arm-smmu-v3: Flush in-flight fault work " sashiko-bot
2026-09-11 0:14 ` Jonathan Cameron
2026-09-10 23:16 ` [PATCH v4 06/15] iommu/arm-smmu-v3: Allocate IOPF queue without FEAT_SVA Nicolin Chen
2026-09-10 23:28 ` sashiko-bot
2026-09-10 23:16 ` [PATCH v4 07/15] iommu/arm-smmu-v3: Submit CMDQ_OP_PRI_RESP for IOPF event Nicolin Chen
2026-09-10 23:36 ` sashiko-bot
2026-09-10 23:17 ` [PATCH v4 08/15] iommu/arm-smmu-v3: Disable the queue IRQs before disabling the SMMU Nicolin Chen
2026-09-10 23:28 ` sashiko-bot
2026-09-10 23:17 ` [PATCH v4 09/15] iommu/arm-smmu-v3: Disable PRI when no IRQ handler is registered Nicolin Chen
2026-09-10 23:36 ` sashiko-bot
2026-09-10 23:17 ` [PATCH v4 10/15] iommu/arm-smmu-v3: Support PRI Page Request in arm_smmu_handle_ppr() Nicolin Chen
2026-09-10 23:35 ` sashiko-bot
2026-09-11 0:14 ` Jonathan Cameron
2026-09-11 23:16 ` Nicolin Chen
2026-09-10 23:17 ` [PATCH v4 11/15] iommu/arm-smmu-v3: Discard partial PRI faults on PRIQ overflow Nicolin Chen
2026-09-10 23:33 ` sashiko-bot
2026-09-11 0:14 ` Jonathan Cameron
2026-09-10 23:17 ` [PATCH v4 12/15] iommu/arm-smmu-v3: Allocate IOPF queue for ARM_SMMU_FEAT_PRI Nicolin Chen
2026-09-10 23:31 ` sashiko-bot
2026-09-10 23:17 ` [PATCH v4 13/15] PCI/ATS: Add PRI stubs Nicolin Chen
2026-09-10 23:25 ` sashiko-bot
2026-09-10 23:17 ` [PATCH v4 14/15] PCI/ATS: Export pci_enable_pri() and pci_reset_pri() Nicolin Chen
2026-09-10 23:28 ` sashiko-bot
2026-09-10 23:17 ` [PATCH v4 15/15] iommu/arm-smmu-v3: Enable PRI for PCI device in arm_smmu_probe_device() Nicolin Chen
2026-09-10 23:36 ` sashiko-bot
2026-09-11 0:14 ` Jonathan Cameron
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=848cb4c8a79da1f434966d998be0f4ebddf80fb7.1789081084.git.nicolinc@nvidia.com \
--to=nicolinc@nvidia.com \
--cc=baolu.lu@linux.intel.com \
--cc=bbiber@nvidia.com \
--cc=bhelgaas@google.com \
--cc=eric.auger@redhat.com \
--cc=harsha.v@oss.qualcomm.com \
--cc=iommu@lists.linux.dev \
--cc=jgg@nvidia.com \
--cc=jonathan.cameron@oss.qualcomm.com \
--cc=joro@8bytes.org \
--cc=jpb@kernel.org \
--cc=kees@kernel.org \
--cc=kevin.tian@intel.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=mmarrid@nvidia.com \
--cc=praan@google.com \
--cc=robin.murphy@arm.com \
--cc=skaestle@nvidia.com \
--cc=skolothumtho@nvidia.com \
--cc=smostafa@google.com \
--cc=will@kernel.org \
/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