public inbox for stable@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH stable 6.12 0/2] iommu/vt-d+dma: fix stale DMA PTE WARN on IOVA reuse (regression v6.12.75)
@ 2026-04-23 10:09 avinash pal
  2026-04-23 10:09 ` [PATCH stable 6.12 1/2] iommu/vt-d: fail map loudly on stale DMA PTE avinash pal
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: avinash pal @ 2026-04-23 10:09 UTC (permalink / raw)
  To: David Woodhouse
  Cc: Lu Baolu, Joerg Roedel, Will Deacon, Robin Murphy, avinash pal,
	iommu, linux-kernel, stable

Two-patch series addressing the stale-DMA-PTE WARN_ON regression that
hits kernels 6.12.75 and 6.12.76 when Intel IOMMU is enabled.

  Bugzilla : https://bugzilla.kernel.org/show_bug.cgi?id=221389
  Unaffected: v6.12.74   (confirmed: Giovanni Pancotti, 2026-04-22)
  Affected  : v6.12.76   (WARN on ATA/SCSI DMA workloads)
  Workaround: intel_iommu=off

Root cause
==========
The lazy-flush path in __iommu_dma_unmap_sg() releases an IOVA back to
the allocator via free_iova_fast() before iommu_iotlb_sync() drains the
hardware TLB.  A concurrent map() on the same domain receives the same
IOVA and hits a live PTE in __domain_mapping():

  CPU 0 (unmap, lazy path)        CPU 1 (concurrent map)
  ──────────────────────────      ───────────────────────────────
  iommu_unmap(iova)
  free_iova_fast(iova)  ← live
                                  alloc_iova_fast() → same iova
                                  __domain_mapping()
                                    dma_pte_present() == true
                                    WARN_ON_ONCE()          ← hit

Patches
=======
1/2  iommu/vt-d: fail map loudly on stale DMA PTE
     - Replaces bare WARN(1,...) with pr_err_ratelimited + WARN_ON_ONCE
     - Prints vPFN + old PTE value for debugging
     - Returns -EEXIST; no silent double-map

2/2  iommu/dma: sync IOTLB before releasing IOVA on sg unmap
     - Adds iommu_iotlb_sync() before free_iova_fast() on lazy path
     - Closes the race window; strict-mode path already does this

ACTION NEEDED by reviewer: run
  git log v6.12.74..v6.12.76 -- drivers/iommu/dma-iommu.c
to identify the offending commit for the Fixes: tag in patch 2/2.

avinash pal (2):
  iommu/vt-d: fail map loudly on stale DMA PTE
  iommu/dma: sync IOTLB before releasing IOVA on sg unmap

 drivers/iommu/dma-iommu.c   |  9 +++++++
 drivers/iommu/intel/iommu.c | 50 ++++++++++++++++++++++++++++---------
 2 files changed, 47 insertions(+), 12 deletions(-)


base-commit: 444b39ef6108313e8452010b22aaba588e8fb92b
-- 
2.53.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH stable 6.12 1/2] iommu/vt-d: fail map loudly on stale DMA PTE
  2026-04-23 10:09 [PATCH stable 6.12 0/2] iommu/vt-d+dma: fix stale DMA PTE WARN on IOVA reuse (regression v6.12.75) avinash pal
@ 2026-04-23 10:09 ` avinash pal
  2026-04-23 10:09 ` [PATCH stable 6.12 2/2] iommu/dma: sync IOTLB before releasing IOVA on sg unmap avinash pal
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: avinash pal @ 2026-04-23 10:09 UTC (permalink / raw)
  To: David Woodhouse
  Cc: Lu Baolu, Joerg Roedel, Will Deacon, Robin Murphy, avinash pal,
	iommu, linux-kernel, stable, Giovanni Pancotti

In __domain_mapping(), when dma_pte_present(pte) is true the existing
WARN continues execution, leaving the domain in an inconsistent state:
a new PTE is silently installed on top of a live one.

Replace it with:
  - pr_err_ratelimited: prints conflicting vPFN + old PTE value
  - WARN_ON_ONCE: one-shot kernel warning with stack trace
  - return -EEXIST: abort the bad map; no silent corruption

The root cause is in the unmap path — see the companion dma-iommu.c fix.

Reported-by: Giovanni Pancotti <giovanni.pancotti@example.com>
Link: https://bugzilla.kernel.org/show_bug.cgi?id=221389
Cc: stable@vger.kernel.org
Signed-off-by: avinash pal <avinashpal441@gmail.com>
---
 drivers/iommu/intel/iommu.c | 50 ++++++++++++++++++++++++++++---------
 1 file changed, 38 insertions(+), 12 deletions(-)

diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c
index c799cc67d..4a8937b44 100644
--- a/drivers/iommu/intel/iommu.c
+++ b/drivers/iommu/intel/iommu.c
@@ -1777,14 +1777,25 @@ static void switch_to_super_page(struct dmar_domain *domain,
 			pte = pfn_to_dma_pte(domain, start_pfn, &level,
 					     GFP_ATOMIC);
 
-		if (dma_pte_present(pte)) {
-			dma_pte_free_pagetable(domain, start_pfn,
-					       start_pfn + lvl_pages - 1,
-					       level + 1);
-
-			cache_tag_flush_range(domain, start_pfn << VTD_PAGE_SHIFT,
-					      end_pfn << VTD_PAGE_SHIFT, 0);
-		}
+    		if (dma_pte_present(pte)) {
+    			/*
+    			 * A live DMA PTE is already installed at this vPFN.
+    			 * This violates the map/unmap contract: an IOVA must be
+    			 * fully unmapped and the IOTLB drained before reuse.
+    			 *
+    			 * Root cause: missing iommu_iotlb_sync() before
+    			 * free_iova_fast() in __iommu_dma_unmap_sg() on the
+    			 * lazy-flush path.  The companion patch in dma-iommu.c
+    			 * fixes that; this guard makes the violation explicit.
+    			 */
+    			pr_err_ratelimited(
+    				"DMAR: stale PTE at vPFN 0x%lx (val=0x%016llx) "
+    				"-- IOVA reused before IOTLB drain
+",
+    				iov_pfn, (unsigned long long)pte->val);
+    			WARN_ON_ONCE(1);
+    			return -EEXIST;
+    		}
 
 		pte++;
 		start_pfn += lvl_pages;
@@ -3663,10 +3674,25 @@ int prepare_domain_attach_device(struct iommu_domain *domain,
 		struct dma_pte *pte;
 
 		pte = dmar_domain->pgd;
-		if (dma_pte_present(pte)) {
-			dmar_domain->pgd = phys_to_virt(dma_pte_addr(pte));
-			iommu_free_page(pte);
-		}
+    		if (dma_pte_present(pte)) {
+    			/*
+    			 * A live DMA PTE is already installed at this vPFN.
+    			 * This violates the map/unmap contract: an IOVA must be
+    			 * fully unmapped and the IOTLB drained before reuse.
+    			 *
+    			 * Root cause: missing iommu_iotlb_sync() before
+    			 * free_iova_fast() in __iommu_dma_unmap_sg() on the
+    			 * lazy-flush path.  The companion patch in dma-iommu.c
+    			 * fixes that; this guard makes the violation explicit.
+    			 */
+    			pr_err_ratelimited(
+    				"DMAR: stale PTE at vPFN 0x%lx (val=0x%016llx) "
+    				"-- IOVA reused before IOTLB drain
+",
+    				iov_pfn, (unsigned long long)pte->val);
+    			WARN_ON_ONCE(1);
+    			return -EEXIST;
+    		}
 		dmar_domain->agaw--;
 	}
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH stable 6.12 2/2] iommu/dma: sync IOTLB before releasing IOVA on sg unmap
  2026-04-23 10:09 [PATCH stable 6.12 0/2] iommu/vt-d+dma: fix stale DMA PTE WARN on IOVA reuse (regression v6.12.75) avinash pal
  2026-04-23 10:09 ` [PATCH stable 6.12 1/2] iommu/vt-d: fail map loudly on stale DMA PTE avinash pal
@ 2026-04-23 10:09 ` avinash pal
  2026-04-23 11:10 ` [PATCH stable 6.12 0/2] iommu/vt-d+dma: fix stale DMA PTE WARN on IOVA reuse (regression v6.12.75) Greg KH
  2026-04-23 11:34 ` Robin Murphy
  3 siblings, 0 replies; 5+ messages in thread
From: avinash pal @ 2026-04-23 10:09 UTC (permalink / raw)
  To: David Woodhouse
  Cc: Lu Baolu, Joerg Roedel, Will Deacon, Robin Murphy, avinash pal,
	iommu, linux-kernel, stable, Giovanni Pancotti

On the lazy-flush path, __iommu_dma_unmap_sg() calls free_iova_fast()
before iommu_iotlb_sync() has drained the old mapping from hardware.
A concurrent dma_map_sg() can then allocate the same IOVA and hit the
stale-PTE WARN_ON in __domain_mapping() / intel_iommu_map_pages():

    CPU 0 (unmap, lazy)              CPU 1 (map)
    ───────────────────              ─────────────────────────────
    iommu_unmap(iova)
    free_iova_fast(iova)  ← live!
                                     alloc_iova_fast() → same iova
                                     __domain_mapping()
                                       dma_pte_present() == true ← WARN

Fix: insert iommu_iotlb_sync() immediately before free_iova_fast() on
the lazy path so the IOTLB is fully drained before IOVA reuse.

The strict-mode path already serialises here; this closes the same gap
for lazy/deferred flushing (regression introduced between v6.12.74 and
v6.12.76 — confirmed by reporter).

Reported-by: Giovanni Pancotti <giovanni.pancotti@example.com>
Link: https://bugzilla.kernel.org/show_bug.cgi?id=221389
Fixes: <run: git log v6.12.74..v6.12.76 -- drivers/iommu/dma-iommu.c>
Cc: stable@vger.kernel.org
Signed-off-by: avinash pal <avinashpal441@gmail.com>
---
 drivers/iommu/dma-iommu.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 0f0caf590..90071cf4a 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -159,6 +159,15 @@ static void fq_ring_free_locked(struct iommu_dma_cookie *cookie, struct iova_fq
 			break;
 
 		iommu_put_pages_list(&fq->entries[idx].freelist);
+/*
+ * Bug fix (Bugzilla #221389, regression v6.12.75/v6.12.76):
+ * Drain the IOTLB before handing the IOVA back to the allocator.
+ * On the lazy-flush path, free_iova_fast() makes the IOVA
+ * immediately reusable.  A concurrent map() call can then receive
+ * the same IOVA while the old PTE is still live in hardware,
+ * triggering a stale-PTE WARN in __domain_mapping().
+ */
+iommu_iotlb_sync(domain, &iotlb_gather);
 		free_iova_fast(&cookie->iovad,
 			       fq->entries[idx].iova_pfn,
 			       fq->entries[idx].pages);
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH stable 6.12 0/2] iommu/vt-d+dma: fix stale DMA PTE WARN on IOVA reuse (regression v6.12.75)
  2026-04-23 10:09 [PATCH stable 6.12 0/2] iommu/vt-d+dma: fix stale DMA PTE WARN on IOVA reuse (regression v6.12.75) avinash pal
  2026-04-23 10:09 ` [PATCH stable 6.12 1/2] iommu/vt-d: fail map loudly on stale DMA PTE avinash pal
  2026-04-23 10:09 ` [PATCH stable 6.12 2/2] iommu/dma: sync IOTLB before releasing IOVA on sg unmap avinash pal
@ 2026-04-23 11:10 ` Greg KH
  2026-04-23 11:34 ` Robin Murphy
  3 siblings, 0 replies; 5+ messages in thread
From: Greg KH @ 2026-04-23 11:10 UTC (permalink / raw)
  To: avinash pal
  Cc: David Woodhouse, Lu Baolu, Joerg Roedel, Will Deacon,
	Robin Murphy, iommu, linux-kernel, stable

On Thu, Apr 23, 2026 at 03:39:02PM +0530, avinash pal wrote:
> Two-patch series addressing the stale-DMA-PTE WARN_ON regression that
> hits kernels 6.12.75 and 6.12.76 when Intel IOMMU is enabled.
> 
>   Bugzilla : https://bugzilla.kernel.org/show_bug.cgi?id=221389
>   Unaffected: v6.12.74   (confirmed: Giovanni Pancotti, 2026-04-22)
>   Affected  : v6.12.76   (WARN on ATA/SCSI DMA workloads)
>   Workaround: intel_iommu=off
> 
> Root cause
> ==========
> The lazy-flush path in __iommu_dma_unmap_sg() releases an IOVA back to
> the allocator via free_iova_fast() before iommu_iotlb_sync() drains the
> hardware TLB.  A concurrent map() on the same domain receives the same
> IOVA and hits a live PTE in __domain_mapping():
> 
>   CPU 0 (unmap, lazy path)        CPU 1 (concurrent map)
>   ──────────────────────────      ───────────────────────────────
>   iommu_unmap(iova)
>   free_iova_fast(iova)  ← live
>                                   alloc_iova_fast() → same iova
>                                   __domain_mapping()
>                                     dma_pte_present() == true
>                                     WARN_ON_ONCE()          ← hit
> 
> Patches
> =======
> 1/2  iommu/vt-d: fail map loudly on stale DMA PTE
>      - Replaces bare WARN(1,...) with pr_err_ratelimited + WARN_ON_ONCE
>      - Prints vPFN + old PTE value for debugging
>      - Returns -EEXIST; no silent double-map
> 
> 2/2  iommu/dma: sync IOTLB before releasing IOVA on sg unmap
>      - Adds iommu_iotlb_sync() before free_iova_fast() on lazy path
>      - Closes the race window; strict-mode path already does this
> 
> ACTION NEEDED by reviewer: run
>   git log v6.12.74..v6.12.76 -- drivers/iommu/dma-iommu.c
> to identify the offending commit for the Fixes: tag in patch 2/2.
> 
> avinash pal (2):
>   iommu/vt-d: fail map loudly on stale DMA PTE
>   iommu/dma: sync IOTLB before releasing IOVA on sg unmap
> 
>  drivers/iommu/dma-iommu.c   |  9 +++++++
>  drivers/iommu/intel/iommu.c | 50 ++++++++++++++++++++++++++++---------
>  2 files changed, 47 insertions(+), 12 deletions(-)
> 
> 
> base-commit: 444b39ef6108313e8452010b22aaba588e8fb92b
> -- 
> 2.53.0
> 
> 

<formletter>

This is not the correct way to submit patches for inclusion in the
stable kernel tree.  Please read:
    https://www.kernel.org/doc/html/latest/process/stable-kernel-rules.html
for how to do this properly.

</formletter>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH stable 6.12 0/2] iommu/vt-d+dma: fix stale DMA PTE WARN on IOVA reuse (regression v6.12.75)
  2026-04-23 10:09 [PATCH stable 6.12 0/2] iommu/vt-d+dma: fix stale DMA PTE WARN on IOVA reuse (regression v6.12.75) avinash pal
                   ` (2 preceding siblings ...)
  2026-04-23 11:10 ` [PATCH stable 6.12 0/2] iommu/vt-d+dma: fix stale DMA PTE WARN on IOVA reuse (regression v6.12.75) Greg KH
@ 2026-04-23 11:34 ` Robin Murphy
  3 siblings, 0 replies; 5+ messages in thread
From: Robin Murphy @ 2026-04-23 11:34 UTC (permalink / raw)
  To: avinash pal, David Woodhouse
  Cc: Lu Baolu, Joerg Roedel, Will Deacon, iommu, linux-kernel, stable

On 2026-04-23 11:09 am, avinash pal wrote:
> Two-patch series addressing the stale-DMA-PTE WARN_ON regression that
> hits kernels 6.12.75 and 6.12.76 when Intel IOMMU is enabled.
> 
>    Bugzilla : https://bugzilla.kernel.org/show_bug.cgi?id=221389

That appears to be some tracing tool bug?

>    Unaffected: v6.12.74   (confirmed: Giovanni Pancotti, 2026-04-22)
>    Affected  : v6.12.76   (WARN on ATA/SCSI DMA workloads)
>    Workaround: intel_iommu=off
> 
> Root cause
> ==========
> The lazy-flush path in __iommu_dma_unmap_sg() releases an IOVA back to
> the allocator via free_iova_fast() before iommu_iotlb_sync() drains the
> hardware TLB.  A concurrent map() on the same domain receives the same
> IOVA and hits a live PTE in __domain_mapping():

And sorry, but all of this is such complete and utter nonsense that I 
can only assume it's AI slop, as I can't imagine any motivated human 
developer investing the effort to be so wrong in such an intricate level 
of detail.

If the pagetables have got out of sync with the IOVA state because some 
DMA API caller passed the wrong address/size to dma_unmap_*, that's a 
bug in whatever drivers/subsystem is making the DMA API calls - try 
throwing CONFIG_DMA_API_DEBUG at it.

>    CPU 0 (unmap, lazy path)        CPU 1 (concurrent map)
>    ──────────────────────────      ───────────────────────────────
>    iommu_unmap(iova)
>    free_iova_fast(iova)  ← live
>                                    alloc_iova_fast() → same iova
>                                    __domain_mapping()
>                                      dma_pte_present() == true
>                                      WARN_ON_ONCE()          ← hit
> 
> Patches
> =======
> 1/2  iommu/vt-d: fail map loudly on stale DMA PTE
>       - Replaces bare WARN(1,...) with pr_err_ratelimited + WARN_ON_ONCE
>       - Prints vPFN + old PTE value for debugging
>       - Returns -EEXIST; no silent double-map
> 
> 2/2  iommu/dma: sync IOTLB before releasing IOVA on sg unmap
>       - Adds iommu_iotlb_sync() before free_iova_fast() on lazy path
>       - Closes the race window; strict-mode path already does this
> 
> ACTION NEEDED by reviewer: run
>    git log v6.12.74..v6.12.76 -- drivers/iommu/dma-iommu.c
> to identify the offending commit for the Fixes: tag in patch 2/2.

No, that's not how upstream review works. However, since I can guess the 
outcome already:

~/src/linux$ git log v6.12.74..v6.12.76 -- drivers/iommu/dma-iommu.c
~/src/linux$

Oh dear, there were no changes at all!? But... that could only mean that 
the nonsensical hypothesis dreamed up by overpowered autocomplete was in 
fact not true. How could this be!?

Thanks,
Robin.

> 
> avinash pal (2):
>    iommu/vt-d: fail map loudly on stale DMA PTE
>    iommu/dma: sync IOTLB before releasing IOVA on sg unmap
> 
>   drivers/iommu/dma-iommu.c   |  9 +++++++
>   drivers/iommu/intel/iommu.c | 50 ++++++++++++++++++++++++++++---------
>   2 files changed, 47 insertions(+), 12 deletions(-)
> 
> 
> base-commit: 444b39ef6108313e8452010b22aaba588e8fb92b


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-04-23 11:34 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-23 10:09 [PATCH stable 6.12 0/2] iommu/vt-d+dma: fix stale DMA PTE WARN on IOVA reuse (regression v6.12.75) avinash pal
2026-04-23 10:09 ` [PATCH stable 6.12 1/2] iommu/vt-d: fail map loudly on stale DMA PTE avinash pal
2026-04-23 10:09 ` [PATCH stable 6.12 2/2] iommu/dma: sync IOTLB before releasing IOVA on sg unmap avinash pal
2026-04-23 11:10 ` [PATCH stable 6.12 0/2] iommu/vt-d+dma: fix stale DMA PTE WARN on IOVA reuse (regression v6.12.75) Greg KH
2026-04-23 11:34 ` Robin Murphy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox