VYPR
Unrated severityNVD Advisory· Published May 27, 2026· Updated May 27, 2026

CVE-2026-45894

CVE-2026-45894

Description

In the Linux kernel, the following vulnerability has been resolved:

iommu/vt-d: Clear Present bit before tearing down PASID entry

The Intel VT-d Scalable Mode PASID table entry consists of 512 bits (64 bytes). When tearing down an entry, the current implementation zeros the entire 64-byte structure immediately using multiple 64-bit writes.

Since the IOMMU hardware may fetch these 64 bytes using multiple internal transactions (e.g., four 128-bit bursts), updating or zeroing the entire entry while it is active (P=1) risks a "torn" read. If a hardware fetch occurs simultaneously with the CPU zeroing the entry, the hardware could observe an inconsistent state, leading to unpredictable behavior or spurious faults.

Follow the "Guidance to Software for Invalidations" in the VT-d spec (Section 6.5.3.3) by implementing the recommended ownership handshake:

1. Clear only the 'Present' (P) bit of the PASID entry. 2. Use a dma_wmb() to ensure the cleared bit is visible to hardware before proceeding. 3. Execute the required invalidation sequence (PASID cache, IOTLB, and Device-TLB flush) to ensure the hardware has released all cached references. 4. Only after the flushes are complete, zero out the remaining fields of the PASID entry.

Also, add a dma_wmb() in pasid_set_present() to ensure that all other fields of the PASID entry are visible to the hardware before the Present bit is set.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

A race condition in Intel VT-d IOMMU PASID table teardown can cause hardware to observe inconsistent state, leading to unpredictable behavior.

Vulnerability

In the Linux kernel's Intel VT-d IOMMU driver, when tearing down a PASID table entry (512-bit structure), the current implementation zeros the entire entry with multiple 64-bit writes while the Present (P) bit is still set. The IOMMU hardware may fetch the entry using multiple internal transactions (e.g., 128-bit bursts), so a concurrent hardware fetch can observe an inconsistent state (torn read). This affects all versions prior to the fix commit [1].

Exploitation

An attacker would need to be able to trigger PASID entry teardown, which typically requires local access and the ability to manage IOMMU mappings (e.g., via device assignment or VFIO). The race window is small but exploitable if an attacker can cause a teardown while the IOMMU is actively using the entry. No special privileges beyond those needed to manage IOMMU contexts are required.

Impact

A successful torn read can lead to unpredictable hardware behavior, including spurious faults, data corruption, or system instability. The attacker may cause denial of service or potentially escalate privileges if the inconsistent state leads to memory access violations.

Mitigation

The fix is included in Linux kernel commit 821807c167b7b48a41b95b6607c6b9f97600f7d9 (stable tree). Users should update to a kernel version containing this commit. No workaround is available; the vulnerability is resolved by the patch. The CVE is not listed on CISA's Known Exploited Vulnerabilities (KEV) catalog as of publication.

AI Insight generated on May 27, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

1

Patches

8
a84d30e8d2ba

iommu/vt-d: Clear Present bit before tearing down PASID entry

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitLu BaoluJan 22, 2026Fixed in 6.12.75via kernel-cna
4 files changed · +38 4
  • drivers/iommu/intel/pasid.c+5 1 modified
    diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
    index 57969ba2d39752..7fa3efb8c223ec 100644
    --- a/drivers/iommu/intel/pasid.c
    +++ b/drivers/iommu/intel/pasid.c
    @@ -252,7 +252,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     
     	did = pasid_get_domain_id(pte);
     	pgtt = pasid_pte_get_pgtt(pte);
    -	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	pasid_clear_present(pte);
     	spin_unlock(&iommu->lock);
     
     	if (!ecap_coherent(iommu->ecap))
    @@ -266,6 +266,10 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     		iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
     
     	devtlb_invalidation_with_pasid(iommu, dev, pasid);
    +	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	if (!ecap_coherent(iommu->ecap))
    +		clflush_cache_range(pte, sizeof(*pte));
    +
     	if (!fault_ignore)
     		intel_iommu_drain_pasid_prq(dev, pasid);
     }
    
  • drivers/iommu/intel/pasid.c+5 1 modified
    diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
    index 57969ba2d39752..7fa3efb8c223ec 100644
    --- a/drivers/iommu/intel/pasid.c
    +++ b/drivers/iommu/intel/pasid.c
    @@ -252,7 +252,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     
     	did = pasid_get_domain_id(pte);
     	pgtt = pasid_pte_get_pgtt(pte);
    -	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	pasid_clear_present(pte);
     	spin_unlock(&iommu->lock);
     
     	if (!ecap_coherent(iommu->ecap))
    @@ -266,6 +266,10 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     		iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
     
     	devtlb_invalidation_with_pasid(iommu, dev, pasid);
    +	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	if (!ecap_coherent(iommu->ecap))
    +		clflush_cache_range(pte, sizeof(*pte));
    +
     	if (!fault_ignore)
     		intel_iommu_drain_pasid_prq(dev, pasid);
     }
    
  • drivers/iommu/intel/pasid.h+14 1 modified
    diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h
    index dde6d3ba5ae0fc..55cad7bfa294e1 100644
    --- a/drivers/iommu/intel/pasid.h
    +++ b/drivers/iommu/intel/pasid.h
    @@ -235,9 +235,23 @@ static inline void pasid_set_wpe(struct pasid_entry *pe)
      */
     static inline void pasid_set_present(struct pasid_entry *pe)
     {
    +	dma_wmb();
     	pasid_set_bits(&pe->val[0], 1 << 0, 1);
     }
     
    +/*
    + * Clear the Present (P) bit (bit 0) of a scalable-mode PASID table entry.
    + * This initiates the transition of the entry's ownership from hardware
    + * to software. The caller is responsible for fulfilling the invalidation
    + * handshake recommended by the VT-d spec, Section 6.5.3.3 (Guidance to
    + * Software for Invalidations).
    + */
    +static inline void pasid_clear_present(struct pasid_entry *pe)
    +{
    +	pasid_set_bits(&pe->val[0], 1 << 0, 0);
    +	dma_wmb();
    +}
    +
     /*
      * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID
      * entry.
    -- 
    cgit 1.3-korg
    
    
    
  • drivers/iommu/intel/pasid.h+14 1 modified
    diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h
    index dde6d3ba5ae0fc..55cad7bfa294e1 100644
    --- a/drivers/iommu/intel/pasid.h
    +++ b/drivers/iommu/intel/pasid.h
    @@ -235,9 +235,23 @@ static inline void pasid_set_wpe(struct pasid_entry *pe)
      */
     static inline void pasid_set_present(struct pasid_entry *pe)
     {
    +	dma_wmb();
     	pasid_set_bits(&pe->val[0], 1 << 0, 1);
     }
     
    +/*
    + * Clear the Present (P) bit (bit 0) of a scalable-mode PASID table entry.
    + * This initiates the transition of the entry's ownership from hardware
    + * to software. The caller is responsible for fulfilling the invalidation
    + * handshake recommended by the VT-d spec, Section 6.5.3.3 (Guidance to
    + * Software for Invalidations).
    + */
    +static inline void pasid_clear_present(struct pasid_entry *pe)
    +{
    +	pasid_set_bits(&pe->val[0], 1 << 0, 0);
    +	dma_wmb();
    +}
    +
     /*
      * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID
      * entry.
    -- 
    cgit 1.3-korg
    
    
    
75ed00055c05

iommu/vt-d: Clear Present bit before tearing down PASID entry

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitLu BaoluJan 22, 2026Fixed in 7.0via kernel-cna
4 files changed · +38 4
  • drivers/iommu/intel/pasid.c+5 1 modified
    diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
    index 6379b211f12b0f..07e056b2460502 100644
    --- a/drivers/iommu/intel/pasid.c
    +++ b/drivers/iommu/intel/pasid.c
    @@ -273,7 +273,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     
     	did = pasid_get_domain_id(pte);
     	pgtt = pasid_pte_get_pgtt(pte);
    -	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	pasid_clear_present(pte);
     	spin_unlock(&iommu->lock);
     
     	if (!ecap_coherent(iommu->ecap))
    @@ -287,6 +287,10 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     		iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
     
     	devtlb_invalidation_with_pasid(iommu, dev, pasid);
    +	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	if (!ecap_coherent(iommu->ecap))
    +		clflush_cache_range(pte, sizeof(*pte));
    +
     	if (!fault_ignore)
     		intel_iommu_drain_pasid_prq(dev, pasid);
     }
    
  • drivers/iommu/intel/pasid.c+5 1 modified
    diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
    index 6379b211f12b0f..07e056b2460502 100644
    --- a/drivers/iommu/intel/pasid.c
    +++ b/drivers/iommu/intel/pasid.c
    @@ -273,7 +273,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     
     	did = pasid_get_domain_id(pte);
     	pgtt = pasid_pte_get_pgtt(pte);
    -	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	pasid_clear_present(pte);
     	spin_unlock(&iommu->lock);
     
     	if (!ecap_coherent(iommu->ecap))
    @@ -287,6 +287,10 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     		iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
     
     	devtlb_invalidation_with_pasid(iommu, dev, pasid);
    +	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	if (!ecap_coherent(iommu->ecap))
    +		clflush_cache_range(pte, sizeof(*pte));
    +
     	if (!fault_ignore)
     		intel_iommu_drain_pasid_prq(dev, pasid);
     }
    
  • drivers/iommu/intel/pasid.h+14 1 modified
    diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h
    index b4c85242dc7962..0b303bd0b0c189 100644
    --- a/drivers/iommu/intel/pasid.h
    +++ b/drivers/iommu/intel/pasid.h
    @@ -234,9 +234,23 @@ static inline void pasid_set_wpe(struct pasid_entry *pe)
      */
     static inline void pasid_set_present(struct pasid_entry *pe)
     {
    +	dma_wmb();
     	pasid_set_bits(&pe->val[0], 1 << 0, 1);
     }
     
    +/*
    + * Clear the Present (P) bit (bit 0) of a scalable-mode PASID table entry.
    + * This initiates the transition of the entry's ownership from hardware
    + * to software. The caller is responsible for fulfilling the invalidation
    + * handshake recommended by the VT-d spec, Section 6.5.3.3 (Guidance to
    + * Software for Invalidations).
    + */
    +static inline void pasid_clear_present(struct pasid_entry *pe)
    +{
    +	pasid_set_bits(&pe->val[0], 1 << 0, 0);
    +	dma_wmb();
    +}
    +
     /*
      * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID
      * entry.
    -- 
    cgit 1.3-korg
    
    
    
  • drivers/iommu/intel/pasid.h+14 1 modified
    diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h
    index b4c85242dc7962..0b303bd0b0c189 100644
    --- a/drivers/iommu/intel/pasid.h
    +++ b/drivers/iommu/intel/pasid.h
    @@ -234,9 +234,23 @@ static inline void pasid_set_wpe(struct pasid_entry *pe)
      */
     static inline void pasid_set_present(struct pasid_entry *pe)
     {
    +	dma_wmb();
     	pasid_set_bits(&pe->val[0], 1 << 0, 1);
     }
     
    +/*
    + * Clear the Present (P) bit (bit 0) of a scalable-mode PASID table entry.
    + * This initiates the transition of the entry's ownership from hardware
    + * to software. The caller is responsible for fulfilling the invalidation
    + * handshake recommended by the VT-d spec, Section 6.5.3.3 (Guidance to
    + * Software for Invalidations).
    + */
    +static inline void pasid_clear_present(struct pasid_entry *pe)
    +{
    +	pasid_set_bits(&pe->val[0], 1 << 0, 0);
    +	dma_wmb();
    +}
    +
     /*
      * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID
      * entry.
    -- 
    cgit 1.3-korg
    
    
    
821807c167b7

iommu/vt-d: Clear Present bit before tearing down PASID entry

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitLu BaoluJan 22, 2026Fixed in 6.18.14via kernel-cna
4 files changed · +38 4
  • drivers/iommu/intel/pasid.c+5 1 modified
    diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
    index 67cbf53d18c8ff..f64b5ae306d0f2 100644
    --- a/drivers/iommu/intel/pasid.c
    +++ b/drivers/iommu/intel/pasid.c
    @@ -273,7 +273,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     
     	did = pasid_get_domain_id(pte);
     	pgtt = pasid_pte_get_pgtt(pte);
    -	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	pasid_clear_present(pte);
     	spin_unlock(&iommu->lock);
     
     	if (!ecap_coherent(iommu->ecap))
    @@ -287,6 +287,10 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     		iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
     
     	devtlb_invalidation_with_pasid(iommu, dev, pasid);
    +	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	if (!ecap_coherent(iommu->ecap))
    +		clflush_cache_range(pte, sizeof(*pte));
    +
     	if (!fault_ignore)
     		intel_iommu_drain_pasid_prq(dev, pasid);
     }
    
  • drivers/iommu/intel/pasid.c+5 1 modified
    diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
    index 67cbf53d18c8ff..f64b5ae306d0f2 100644
    --- a/drivers/iommu/intel/pasid.c
    +++ b/drivers/iommu/intel/pasid.c
    @@ -273,7 +273,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     
     	did = pasid_get_domain_id(pte);
     	pgtt = pasid_pte_get_pgtt(pte);
    -	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	pasid_clear_present(pte);
     	spin_unlock(&iommu->lock);
     
     	if (!ecap_coherent(iommu->ecap))
    @@ -287,6 +287,10 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     		iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
     
     	devtlb_invalidation_with_pasid(iommu, dev, pasid);
    +	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	if (!ecap_coherent(iommu->ecap))
    +		clflush_cache_range(pte, sizeof(*pte));
    +
     	if (!fault_ignore)
     		intel_iommu_drain_pasid_prq(dev, pasid);
     }
    
  • drivers/iommu/intel/pasid.h+14 1 modified
    diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h
    index a771a77d4239c4..637373995be803 100644
    --- a/drivers/iommu/intel/pasid.h
    +++ b/drivers/iommu/intel/pasid.h
    @@ -233,9 +233,23 @@ static inline void pasid_set_wpe(struct pasid_entry *pe)
      */
     static inline void pasid_set_present(struct pasid_entry *pe)
     {
    +	dma_wmb();
     	pasid_set_bits(&pe->val[0], 1 << 0, 1);
     }
     
    +/*
    + * Clear the Present (P) bit (bit 0) of a scalable-mode PASID table entry.
    + * This initiates the transition of the entry's ownership from hardware
    + * to software. The caller is responsible for fulfilling the invalidation
    + * handshake recommended by the VT-d spec, Section 6.5.3.3 (Guidance to
    + * Software for Invalidations).
    + */
    +static inline void pasid_clear_present(struct pasid_entry *pe)
    +{
    +	pasid_set_bits(&pe->val[0], 1 << 0, 0);
    +	dma_wmb();
    +}
    +
     /*
      * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID
      * entry.
    -- 
    cgit 1.3-korg
    
    
    
  • drivers/iommu/intel/pasid.h+14 1 modified
    diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h
    index a771a77d4239c4..637373995be803 100644
    --- a/drivers/iommu/intel/pasid.h
    +++ b/drivers/iommu/intel/pasid.h
    @@ -233,9 +233,23 @@ static inline void pasid_set_wpe(struct pasid_entry *pe)
      */
     static inline void pasid_set_present(struct pasid_entry *pe)
     {
    +	dma_wmb();
     	pasid_set_bits(&pe->val[0], 1 << 0, 1);
     }
     
    +/*
    + * Clear the Present (P) bit (bit 0) of a scalable-mode PASID table entry.
    + * This initiates the transition of the entry's ownership from hardware
    + * to software. The caller is responsible for fulfilling the invalidation
    + * handshake recommended by the VT-d spec, Section 6.5.3.3 (Guidance to
    + * Software for Invalidations).
    + */
    +static inline void pasid_clear_present(struct pasid_entry *pe)
    +{
    +	pasid_set_bits(&pe->val[0], 1 << 0, 0);
    +	dma_wmb();
    +}
    +
     /*
      * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID
      * entry.
    -- 
    cgit 1.3-korg
    
    
    
949d71666e9d

iommu/vt-d: Clear Present bit before tearing down PASID entry

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.gitLu BaoluJan 22, 2026Fixed in 6.19.4via kernel-cna
4 files changed · +38 4
  • drivers/iommu/intel/pasid.c+5 1 modified
    diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
    index 77b9b147ab50e5..b611ad070e729c 100644
    --- a/drivers/iommu/intel/pasid.c
    +++ b/drivers/iommu/intel/pasid.c
    @@ -273,7 +273,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     
     	did = pasid_get_domain_id(pte);
     	pgtt = pasid_pte_get_pgtt(pte);
    -	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	pasid_clear_present(pte);
     	spin_unlock(&iommu->lock);
     
     	if (!ecap_coherent(iommu->ecap))
    @@ -287,6 +287,10 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     		iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
     
     	devtlb_invalidation_with_pasid(iommu, dev, pasid);
    +	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	if (!ecap_coherent(iommu->ecap))
    +		clflush_cache_range(pte, sizeof(*pte));
    +
     	if (!fault_ignore)
     		intel_iommu_drain_pasid_prq(dev, pasid);
     }
    
  • drivers/iommu/intel/pasid.c+5 1 modified
    diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
    index 77b9b147ab50e5..b611ad070e729c 100644
    --- a/drivers/iommu/intel/pasid.c
    +++ b/drivers/iommu/intel/pasid.c
    @@ -273,7 +273,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     
     	did = pasid_get_domain_id(pte);
     	pgtt = pasid_pte_get_pgtt(pte);
    -	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	pasid_clear_present(pte);
     	spin_unlock(&iommu->lock);
     
     	if (!ecap_coherent(iommu->ecap))
    @@ -287,6 +287,10 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     		iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
     
     	devtlb_invalidation_with_pasid(iommu, dev, pasid);
    +	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	if (!ecap_coherent(iommu->ecap))
    +		clflush_cache_range(pte, sizeof(*pte));
    +
     	if (!fault_ignore)
     		intel_iommu_drain_pasid_prq(dev, pasid);
     }
    
  • drivers/iommu/intel/pasid.h+14 1 modified
    diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h
    index 3809793e0259f1..b67b2dc4ad9c02 100644
    --- a/drivers/iommu/intel/pasid.h
    +++ b/drivers/iommu/intel/pasid.h
    @@ -234,9 +234,23 @@ static inline void pasid_set_wpe(struct pasid_entry *pe)
      */
     static inline void pasid_set_present(struct pasid_entry *pe)
     {
    +	dma_wmb();
     	pasid_set_bits(&pe->val[0], 1 << 0, 1);
     }
     
    +/*
    + * Clear the Present (P) bit (bit 0) of a scalable-mode PASID table entry.
    + * This initiates the transition of the entry's ownership from hardware
    + * to software. The caller is responsible for fulfilling the invalidation
    + * handshake recommended by the VT-d spec, Section 6.5.3.3 (Guidance to
    + * Software for Invalidations).
    + */
    +static inline void pasid_clear_present(struct pasid_entry *pe)
    +{
    +	pasid_set_bits(&pe->val[0], 1 << 0, 0);
    +	dma_wmb();
    +}
    +
     /*
      * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID
      * entry.
    -- 
    cgit 1.3-korg
    
    
    
  • drivers/iommu/intel/pasid.h+14 1 modified
    diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h
    index 3809793e0259f1..b67b2dc4ad9c02 100644
    --- a/drivers/iommu/intel/pasid.h
    +++ b/drivers/iommu/intel/pasid.h
    @@ -234,9 +234,23 @@ static inline void pasid_set_wpe(struct pasid_entry *pe)
      */
     static inline void pasid_set_present(struct pasid_entry *pe)
     {
    +	dma_wmb();
     	pasid_set_bits(&pe->val[0], 1 << 0, 1);
     }
     
    +/*
    + * Clear the Present (P) bit (bit 0) of a scalable-mode PASID table entry.
    + * This initiates the transition of the entry's ownership from hardware
    + * to software. The caller is responsible for fulfilling the invalidation
    + * handshake recommended by the VT-d spec, Section 6.5.3.3 (Guidance to
    + * Software for Invalidations).
    + */
    +static inline void pasid_clear_present(struct pasid_entry *pe)
    +{
    +	pasid_set_bits(&pe->val[0], 1 << 0, 0);
    +	dma_wmb();
    +}
    +
     /*
      * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID
      * entry.
    -- 
    cgit 1.3-korg
    
    
    
75ed00055c05

iommu/vt-d: Clear Present bit before tearing down PASID entry

4 files changed · +38 4
  • drivers/iommu/intel/pasid.c+5 1 modified
    diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
    index 6379b211f12b0f..07e056b2460502 100644
    --- a/drivers/iommu/intel/pasid.c
    +++ b/drivers/iommu/intel/pasid.c
    @@ -273,7 +273,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     
     	did = pasid_get_domain_id(pte);
     	pgtt = pasid_pte_get_pgtt(pte);
    -	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	pasid_clear_present(pte);
     	spin_unlock(&iommu->lock);
     
     	if (!ecap_coherent(iommu->ecap))
    @@ -287,6 +287,10 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     		iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
     
     	devtlb_invalidation_with_pasid(iommu, dev, pasid);
    +	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	if (!ecap_coherent(iommu->ecap))
    +		clflush_cache_range(pte, sizeof(*pte));
    +
     	if (!fault_ignore)
     		intel_iommu_drain_pasid_prq(dev, pasid);
     }
    
  • drivers/iommu/intel/pasid.c+5 1 modified
    diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
    index 6379b211f12b0f..07e056b2460502 100644
    --- a/drivers/iommu/intel/pasid.c
    +++ b/drivers/iommu/intel/pasid.c
    @@ -273,7 +273,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     
     	did = pasid_get_domain_id(pte);
     	pgtt = pasid_pte_get_pgtt(pte);
    -	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	pasid_clear_present(pte);
     	spin_unlock(&iommu->lock);
     
     	if (!ecap_coherent(iommu->ecap))
    @@ -287,6 +287,10 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     		iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
     
     	devtlb_invalidation_with_pasid(iommu, dev, pasid);
    +	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	if (!ecap_coherent(iommu->ecap))
    +		clflush_cache_range(pte, sizeof(*pte));
    +
     	if (!fault_ignore)
     		intel_iommu_drain_pasid_prq(dev, pasid);
     }
    
  • drivers/iommu/intel/pasid.h+14 1 modified
    diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h
    index b4c85242dc7962..0b303bd0b0c189 100644
    --- a/drivers/iommu/intel/pasid.h
    +++ b/drivers/iommu/intel/pasid.h
    @@ -234,9 +234,23 @@ static inline void pasid_set_wpe(struct pasid_entry *pe)
      */
     static inline void pasid_set_present(struct pasid_entry *pe)
     {
    +	dma_wmb();
     	pasid_set_bits(&pe->val[0], 1 << 0, 1);
     }
     
    +/*
    + * Clear the Present (P) bit (bit 0) of a scalable-mode PASID table entry.
    + * This initiates the transition of the entry's ownership from hardware
    + * to software. The caller is responsible for fulfilling the invalidation
    + * handshake recommended by the VT-d spec, Section 6.5.3.3 (Guidance to
    + * Software for Invalidations).
    + */
    +static inline void pasid_clear_present(struct pasid_entry *pe)
    +{
    +	pasid_set_bits(&pe->val[0], 1 << 0, 0);
    +	dma_wmb();
    +}
    +
     /*
      * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID
      * entry.
    -- 
    cgit 1.3-korg
    
    
    
  • drivers/iommu/intel/pasid.h+14 1 modified
    diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h
    index b4c85242dc7962..0b303bd0b0c189 100644
    --- a/drivers/iommu/intel/pasid.h
    +++ b/drivers/iommu/intel/pasid.h
    @@ -234,9 +234,23 @@ static inline void pasid_set_wpe(struct pasid_entry *pe)
      */
     static inline void pasid_set_present(struct pasid_entry *pe)
     {
    +	dma_wmb();
     	pasid_set_bits(&pe->val[0], 1 << 0, 1);
     }
     
    +/*
    + * Clear the Present (P) bit (bit 0) of a scalable-mode PASID table entry.
    + * This initiates the transition of the entry's ownership from hardware
    + * to software. The caller is responsible for fulfilling the invalidation
    + * handshake recommended by the VT-d spec, Section 6.5.3.3 (Guidance to
    + * Software for Invalidations).
    + */
    +static inline void pasid_clear_present(struct pasid_entry *pe)
    +{
    +	pasid_set_bits(&pe->val[0], 1 << 0, 0);
    +	dma_wmb();
    +}
    +
     /*
      * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID
      * entry.
    -- 
    cgit 1.3-korg
    
    
    
949d71666e9d

iommu/vt-d: Clear Present bit before tearing down PASID entry

4 files changed · +38 4
  • drivers/iommu/intel/pasid.c+5 1 modified
    diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
    index 77b9b147ab50e5..b611ad070e729c 100644
    --- a/drivers/iommu/intel/pasid.c
    +++ b/drivers/iommu/intel/pasid.c
    @@ -273,7 +273,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     
     	did = pasid_get_domain_id(pte);
     	pgtt = pasid_pte_get_pgtt(pte);
    -	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	pasid_clear_present(pte);
     	spin_unlock(&iommu->lock);
     
     	if (!ecap_coherent(iommu->ecap))
    @@ -287,6 +287,10 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     		iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
     
     	devtlb_invalidation_with_pasid(iommu, dev, pasid);
    +	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	if (!ecap_coherent(iommu->ecap))
    +		clflush_cache_range(pte, sizeof(*pte));
    +
     	if (!fault_ignore)
     		intel_iommu_drain_pasid_prq(dev, pasid);
     }
    
  • drivers/iommu/intel/pasid.c+5 1 modified
    diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
    index 77b9b147ab50e5..b611ad070e729c 100644
    --- a/drivers/iommu/intel/pasid.c
    +++ b/drivers/iommu/intel/pasid.c
    @@ -273,7 +273,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     
     	did = pasid_get_domain_id(pte);
     	pgtt = pasid_pte_get_pgtt(pte);
    -	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	pasid_clear_present(pte);
     	spin_unlock(&iommu->lock);
     
     	if (!ecap_coherent(iommu->ecap))
    @@ -287,6 +287,10 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     		iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
     
     	devtlb_invalidation_with_pasid(iommu, dev, pasid);
    +	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	if (!ecap_coherent(iommu->ecap))
    +		clflush_cache_range(pte, sizeof(*pte));
    +
     	if (!fault_ignore)
     		intel_iommu_drain_pasid_prq(dev, pasid);
     }
    
  • drivers/iommu/intel/pasid.h+14 1 modified
    diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h
    index 3809793e0259f1..b67b2dc4ad9c02 100644
    --- a/drivers/iommu/intel/pasid.h
    +++ b/drivers/iommu/intel/pasid.h
    @@ -234,9 +234,23 @@ static inline void pasid_set_wpe(struct pasid_entry *pe)
      */
     static inline void pasid_set_present(struct pasid_entry *pe)
     {
    +	dma_wmb();
     	pasid_set_bits(&pe->val[0], 1 << 0, 1);
     }
     
    +/*
    + * Clear the Present (P) bit (bit 0) of a scalable-mode PASID table entry.
    + * This initiates the transition of the entry's ownership from hardware
    + * to software. The caller is responsible for fulfilling the invalidation
    + * handshake recommended by the VT-d spec, Section 6.5.3.3 (Guidance to
    + * Software for Invalidations).
    + */
    +static inline void pasid_clear_present(struct pasid_entry *pe)
    +{
    +	pasid_set_bits(&pe->val[0], 1 << 0, 0);
    +	dma_wmb();
    +}
    +
     /*
      * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID
      * entry.
    -- 
    cgit 1.3-korg
    
    
    
  • drivers/iommu/intel/pasid.h+14 1 modified
    diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h
    index 3809793e0259f1..b67b2dc4ad9c02 100644
    --- a/drivers/iommu/intel/pasid.h
    +++ b/drivers/iommu/intel/pasid.h
    @@ -234,9 +234,23 @@ static inline void pasid_set_wpe(struct pasid_entry *pe)
      */
     static inline void pasid_set_present(struct pasid_entry *pe)
     {
    +	dma_wmb();
     	pasid_set_bits(&pe->val[0], 1 << 0, 1);
     }
     
    +/*
    + * Clear the Present (P) bit (bit 0) of a scalable-mode PASID table entry.
    + * This initiates the transition of the entry's ownership from hardware
    + * to software. The caller is responsible for fulfilling the invalidation
    + * handshake recommended by the VT-d spec, Section 6.5.3.3 (Guidance to
    + * Software for Invalidations).
    + */
    +static inline void pasid_clear_present(struct pasid_entry *pe)
    +{
    +	pasid_set_bits(&pe->val[0], 1 << 0, 0);
    +	dma_wmb();
    +}
    +
     /*
      * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID
      * entry.
    -- 
    cgit 1.3-korg
    
    
    
a84d30e8d2ba

iommu/vt-d: Clear Present bit before tearing down PASID entry

4 files changed · +38 4
  • drivers/iommu/intel/pasid.c+5 1 modified
    diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
    index 57969ba2d39752..7fa3efb8c223ec 100644
    --- a/drivers/iommu/intel/pasid.c
    +++ b/drivers/iommu/intel/pasid.c
    @@ -252,7 +252,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     
     	did = pasid_get_domain_id(pte);
     	pgtt = pasid_pte_get_pgtt(pte);
    -	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	pasid_clear_present(pte);
     	spin_unlock(&iommu->lock);
     
     	if (!ecap_coherent(iommu->ecap))
    @@ -266,6 +266,10 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     		iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
     
     	devtlb_invalidation_with_pasid(iommu, dev, pasid);
    +	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	if (!ecap_coherent(iommu->ecap))
    +		clflush_cache_range(pte, sizeof(*pte));
    +
     	if (!fault_ignore)
     		intel_iommu_drain_pasid_prq(dev, pasid);
     }
    
  • drivers/iommu/intel/pasid.c+5 1 modified
    diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
    index 57969ba2d39752..7fa3efb8c223ec 100644
    --- a/drivers/iommu/intel/pasid.c
    +++ b/drivers/iommu/intel/pasid.c
    @@ -252,7 +252,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     
     	did = pasid_get_domain_id(pte);
     	pgtt = pasid_pte_get_pgtt(pte);
    -	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	pasid_clear_present(pte);
     	spin_unlock(&iommu->lock);
     
     	if (!ecap_coherent(iommu->ecap))
    @@ -266,6 +266,10 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     		iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
     
     	devtlb_invalidation_with_pasid(iommu, dev, pasid);
    +	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	if (!ecap_coherent(iommu->ecap))
    +		clflush_cache_range(pte, sizeof(*pte));
    +
     	if (!fault_ignore)
     		intel_iommu_drain_pasid_prq(dev, pasid);
     }
    
  • drivers/iommu/intel/pasid.h+14 1 modified
    diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h
    index dde6d3ba5ae0fc..55cad7bfa294e1 100644
    --- a/drivers/iommu/intel/pasid.h
    +++ b/drivers/iommu/intel/pasid.h
    @@ -235,9 +235,23 @@ static inline void pasid_set_wpe(struct pasid_entry *pe)
      */
     static inline void pasid_set_present(struct pasid_entry *pe)
     {
    +	dma_wmb();
     	pasid_set_bits(&pe->val[0], 1 << 0, 1);
     }
     
    +/*
    + * Clear the Present (P) bit (bit 0) of a scalable-mode PASID table entry.
    + * This initiates the transition of the entry's ownership from hardware
    + * to software. The caller is responsible for fulfilling the invalidation
    + * handshake recommended by the VT-d spec, Section 6.5.3.3 (Guidance to
    + * Software for Invalidations).
    + */
    +static inline void pasid_clear_present(struct pasid_entry *pe)
    +{
    +	pasid_set_bits(&pe->val[0], 1 << 0, 0);
    +	dma_wmb();
    +}
    +
     /*
      * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID
      * entry.
    -- 
    cgit 1.3-korg
    
    
    
  • drivers/iommu/intel/pasid.h+14 1 modified
    diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h
    index dde6d3ba5ae0fc..55cad7bfa294e1 100644
    --- a/drivers/iommu/intel/pasid.h
    +++ b/drivers/iommu/intel/pasid.h
    @@ -235,9 +235,23 @@ static inline void pasid_set_wpe(struct pasid_entry *pe)
      */
     static inline void pasid_set_present(struct pasid_entry *pe)
     {
    +	dma_wmb();
     	pasid_set_bits(&pe->val[0], 1 << 0, 1);
     }
     
    +/*
    + * Clear the Present (P) bit (bit 0) of a scalable-mode PASID table entry.
    + * This initiates the transition of the entry's ownership from hardware
    + * to software. The caller is responsible for fulfilling the invalidation
    + * handshake recommended by the VT-d spec, Section 6.5.3.3 (Guidance to
    + * Software for Invalidations).
    + */
    +static inline void pasid_clear_present(struct pasid_entry *pe)
    +{
    +	pasid_set_bits(&pe->val[0], 1 << 0, 0);
    +	dma_wmb();
    +}
    +
     /*
      * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID
      * entry.
    -- 
    cgit 1.3-korg
    
    
    
821807c167b7

iommu/vt-d: Clear Present bit before tearing down PASID entry

4 files changed · +38 4
  • drivers/iommu/intel/pasid.c+5 1 modified
    diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
    index 67cbf53d18c8ff..f64b5ae306d0f2 100644
    --- a/drivers/iommu/intel/pasid.c
    +++ b/drivers/iommu/intel/pasid.c
    @@ -273,7 +273,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     
     	did = pasid_get_domain_id(pte);
     	pgtt = pasid_pte_get_pgtt(pte);
    -	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	pasid_clear_present(pte);
     	spin_unlock(&iommu->lock);
     
     	if (!ecap_coherent(iommu->ecap))
    @@ -287,6 +287,10 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     		iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
     
     	devtlb_invalidation_with_pasid(iommu, dev, pasid);
    +	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	if (!ecap_coherent(iommu->ecap))
    +		clflush_cache_range(pte, sizeof(*pte));
    +
     	if (!fault_ignore)
     		intel_iommu_drain_pasid_prq(dev, pasid);
     }
    
  • drivers/iommu/intel/pasid.c+5 1 modified
    diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c
    index 67cbf53d18c8ff..f64b5ae306d0f2 100644
    --- a/drivers/iommu/intel/pasid.c
    +++ b/drivers/iommu/intel/pasid.c
    @@ -273,7 +273,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     
     	did = pasid_get_domain_id(pte);
     	pgtt = pasid_pte_get_pgtt(pte);
    -	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	pasid_clear_present(pte);
     	spin_unlock(&iommu->lock);
     
     	if (!ecap_coherent(iommu->ecap))
    @@ -287,6 +287,10 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev,
     		iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH);
     
     	devtlb_invalidation_with_pasid(iommu, dev, pasid);
    +	intel_pasid_clear_entry(dev, pasid, fault_ignore);
    +	if (!ecap_coherent(iommu->ecap))
    +		clflush_cache_range(pte, sizeof(*pte));
    +
     	if (!fault_ignore)
     		intel_iommu_drain_pasid_prq(dev, pasid);
     }
    
  • drivers/iommu/intel/pasid.h+14 1 modified
    diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h
    index a771a77d4239c4..637373995be803 100644
    --- a/drivers/iommu/intel/pasid.h
    +++ b/drivers/iommu/intel/pasid.h
    @@ -233,9 +233,23 @@ static inline void pasid_set_wpe(struct pasid_entry *pe)
      */
     static inline void pasid_set_present(struct pasid_entry *pe)
     {
    +	dma_wmb();
     	pasid_set_bits(&pe->val[0], 1 << 0, 1);
     }
     
    +/*
    + * Clear the Present (P) bit (bit 0) of a scalable-mode PASID table entry.
    + * This initiates the transition of the entry's ownership from hardware
    + * to software. The caller is responsible for fulfilling the invalidation
    + * handshake recommended by the VT-d spec, Section 6.5.3.3 (Guidance to
    + * Software for Invalidations).
    + */
    +static inline void pasid_clear_present(struct pasid_entry *pe)
    +{
    +	pasid_set_bits(&pe->val[0], 1 << 0, 0);
    +	dma_wmb();
    +}
    +
     /*
      * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID
      * entry.
    -- 
    cgit 1.3-korg
    
    
    
  • drivers/iommu/intel/pasid.h+14 1 modified
    diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h
    index a771a77d4239c4..637373995be803 100644
    --- a/drivers/iommu/intel/pasid.h
    +++ b/drivers/iommu/intel/pasid.h
    @@ -233,9 +233,23 @@ static inline void pasid_set_wpe(struct pasid_entry *pe)
      */
     static inline void pasid_set_present(struct pasid_entry *pe)
     {
    +	dma_wmb();
     	pasid_set_bits(&pe->val[0], 1 << 0, 1);
     }
     
    +/*
    + * Clear the Present (P) bit (bit 0) of a scalable-mode PASID table entry.
    + * This initiates the transition of the entry's ownership from hardware
    + * to software. The caller is responsible for fulfilling the invalidation
    + * handshake recommended by the VT-d spec, Section 6.5.3.3 (Guidance to
    + * Software for Invalidations).
    + */
    +static inline void pasid_clear_present(struct pasid_entry *pe)
    +{
    +	pasid_set_bits(&pe->val[0], 1 << 0, 0);
    +	dma_wmb();
    +}
    +
     /*
      * Setup Page Walk Snoop bit (Bit 87) of a scalable mode PASID
      * entry.
    -- 
    cgit 1.3-korg
    
    
    

Vulnerability mechanics

Root cause

"Missing ownership handshake: zeroing the entire 64-byte PASID entry while the Present bit is still set allows the IOMMU hardware to observe a torn/inconsistent state during concurrent fetches."

Attack vector

An attacker with the ability to trigger IOMMU PASID entry teardown (e.g., through device driver unbind, process exit, or IOMMU domain destruction) can cause the CPU to zero the 64-byte PASID table entry while the IOMMU hardware may concurrently fetch it. Because the hardware may read the entry in multiple internal transactions (e.g., four 128-bit bursts), a torn read can occur where the hardware observes an inconsistent state — some fields zeroed, others still valid — leading to unpredictable IOMMU behavior or spurious faults. No special network path or authentication bypass is required; the precondition is that a PASID entry with P=1 is being torn down.

Affected code

The vulnerability is in `drivers/iommu/intel/pasid.c` in the function `intel_pasid_tear_down_entry()` and in `drivers/iommu/intel/pasid.h` in the inline helpers `pasid_set_present()` and the newly added `pasid_clear_present()`. The fault lies in the teardown path: the old code called `intel_pasid_clear_entry()` (which zeros the entire 64-byte PASID entry) while the Present bit (P=1) was still set, before performing any cache or TLB invalidations [patch_id=2661588].

What the fix does

The patch implements a proper ownership handshake per VT-d spec Section 6.5.3.3. In `intel_pasid_tear_down_entry()`, the old `intel_pasid_clear_entry()` call (which zeroes the whole entry) is replaced with `pasid_clear_present()`, which clears only bit 0 (the Present bit) and issues a `dma_wmb()` to make that write visible to hardware. After releasing the spinlock, the existing invalidation sequence (PASID cache, IOTLB, Device-TLB flush) runs. Only after those flushes complete does the code call `intel_pasid_clear_entry()` to zero the remaining fields. Additionally, a `dma_wmb()` is added to `pasid_set_present()` to ensure all other entry fields are visible before the Present bit is set [patch_id=2661588].

Preconditions

  • configA PASID entry with the Present (P) bit set must be torn down via intel_pasid_tear_down_entry()
  • configThe IOMMU hardware must be in scalable mode (PASID table entries are 64 bytes)
  • authNo special authentication or network access required; the attacker triggers teardown through normal device/process lifecycle operations

Generated on May 27, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.