]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
iommu/vt-d: Clear Present bit before tearing down scalable-mode context entry
authorMichael Bommarito <michael.bommarito@gmail.com>
Thu, 4 Jun 2026 06:03:07 +0000 (14:03 +0800)
committerJoerg Roedel <joerg.roedel@amd.com>
Thu, 4 Jun 2026 07:21:49 +0000 (09:21 +0200)
device_pasid_table_teardown() zeroes the 128-bit scalable-mode context
entry with context_clear_entry() while the Present bit is still set. This
creates a window where the hardware can fetch a torn entry, with some
fields already zeroed while Present is still set, leading to unpredictable
behavior or spurious faults. The context-cache invalidation is issued only
after the entry has been zeroed, and intel_pasid_free_table() then frees
the PASID directory pages, so the IOMMU can keep walking a stale Present=1
entry that points at freed memory.

While x86 provides strong write ordering, the compiler may reorder the two
64-bit writes to the entry, and the hardware fetch is not guaranteed to be
atomic with respect to multiple CPU writes.

Commit c1e4f1dccbe9d ("iommu/vt-d: Clear Present bit before tearing down
context entry") fixed this exact pattern in domain_context_clear_one() and
the copied-context path, but device_pasid_table_teardown() was not
converted.

Align it with the "Guidance to Software for Invalidations" in the VT-d
spec, Section 6.5.3.3, using the same ownership handshake as the sibling
fix: clear only the Present bit, flush it to the IOMMU, perform the
context-cache invalidation, and only then zero the rest of the entry.

Fixes: 81e921fd32161 ("iommu/vt-d: Fix NULL domain on device release")
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Assisted-by: Claude:claude-opus-4-7
Link: https://lore.kernel.org/r/20260528025557.3209367-1-michael.bommarito@gmail.com
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
drivers/iommu/intel/pasid.c

index 89541b74ab8ca3c2ebab0b5f60c43743b45c14a8..40910dc7363b133da4be3b29524ad93d4e6bc0aa 100644 (file)
@@ -748,10 +748,12 @@ static void device_pasid_table_teardown(struct device *dev, u8 bus, u8 devfn)
        }
 
        did = context_domain_id(context);
-       context_clear_entry(context);
+       context_clear_present(context);
        __iommu_flush_cache(iommu, context, sizeof(*context));
        spin_unlock(&iommu->lock);
        intel_context_flush_no_pasid(info, context, did);
+       context_clear_entry(context);
+       __iommu_flush_cache(iommu, context, sizeof(*context));
 }
 
 static int pci_pasid_table_teardown(struct pci_dev *pdev, u16 alias, void *data)