[PATCH 2/2] iommu: Use the user PGD for SVA if PTI is enabled

Jacob Pan posted 2 patches 3 years, 7 months ago
[PATCH 2/2] iommu: Use the user PGD for SVA if PTI is enabled
Posted by Jacob Pan 3 years, 7 months ago
With page table isolation, the kernel manages two sets of page tables
for each process: one for user one for kernel. When enabling SVA, the
current x86 IOMMU drivers bind device and PASID with the kernel copy
of the process page table.

While there is no known "Meltdown" type of DMA attack, exposing
kernel mapping to DMA intended for userspace makes the system vulnerable
unnecessarily. It also breaks the intention of PTI.

This patch replaces kernel page table PGD with the user counterpart,
thus fulfill the promise of PTI on the DMA side.

Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
---
 drivers/iommu/amd/iommu_v2.c | 4 +++-
 drivers/iommu/intel/svm.c    | 5 ++++-
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/amd/iommu_v2.c b/drivers/iommu/amd/iommu_v2.c
index 696d5555be57..aea3075b94af 100644
--- a/drivers/iommu/amd/iommu_v2.c
+++ b/drivers/iommu/amd/iommu_v2.c
@@ -600,6 +600,7 @@ int amd_iommu_bind_pasid(struct pci_dev *pdev, u32 pasid,
 	struct pasid_state *pasid_state;
 	struct device_state *dev_state;
 	struct mm_struct *mm;
+	pgd_t *pgd;
 	u32 sbdf;
 	int ret;
 
@@ -645,8 +646,9 @@ int amd_iommu_bind_pasid(struct pci_dev *pdev, u32 pasid,
 	if (ret)
 		goto out_unregister;
 
+	pgd = static_cpu_has(X86_FEATURE_PTI) ? kernel_to_user_pgdp(mm->pgd) : mm->pgd;
 	ret = amd_iommu_domain_set_gcr3(dev_state->domain, pasid,
-					__pa(pasid_state->mm->pgd));
+					__pa(pgd));
 	if (ret)
 		goto out_clear_state;
 
diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c
index 8bcfb93dda56..7472cd98d3e8 100644
--- a/drivers/iommu/intel/svm.c
+++ b/drivers/iommu/intel/svm.c
@@ -332,6 +332,7 @@ static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,
 	struct intel_svm *svm;
 	unsigned long sflags;
 	int ret = 0;
+	pgd_t *pgd;
 
 	svm = pasid_private_find(mm->pasid);
 	if (!svm) {
@@ -394,7 +395,9 @@ static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,
 	sflags = (flags & SVM_FLAG_SUPERVISOR_MODE) ?
 			PASID_FLAG_SUPERVISOR_MODE : 0;
 	sflags |= cpu_feature_enabled(X86_FEATURE_LA57) ? PASID_FLAG_FL5LP : 0;
-	ret = intel_pasid_setup_first_level(iommu, dev, mm->pgd, mm->pasid,
+
+	pgd = static_cpu_has(X86_FEATURE_PTI) ? kernel_to_user_pgdp(mm->pgd) : mm->pgd;
+	ret = intel_pasid_setup_first_level(iommu, dev, pgd, mm->pasid,
 					    FLPT_DEFAULT_DID, sflags);
 	if (ret)
 		goto free_sdev;
-- 
2.25.1
Re: [PATCH 2/2] iommu: Use the user PGD for SVA if PTI is enabled
Posted by Baolu Lu 3 years, 7 months ago
On 8/23/22 4:12 AM, Jacob Pan wrote:
> With page table isolation, the kernel manages two sets of page tables
> for each process: one for user one for kernel. When enabling SVA, the
> current x86 IOMMU drivers bind device and PASID with the kernel copy
> of the process page table.
> 
> While there is no known "Meltdown" type of DMA attack, exposing
> kernel mapping to DMA intended for userspace makes the system vulnerable
> unnecessarily. It also breaks the intention of PTI.
> 
> This patch replaces kernel page table PGD with the user counterpart,
> thus fulfill the promise of PTI on the DMA side.
> 
> Signed-off-by: Jacob Pan<jacob.jun.pan@linux.intel.com>

Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com>

Best regards,
baolu
Re: [PATCH 2/2] iommu: Use the user PGD for SVA if PTI is enabled
Posted by Dave Hansen 3 years, 7 months ago
On 8/22/22 13:12, Jacob Pan wrote:
> @@ -394,7 +395,9 @@ static struct iommu_sva *intel_svm_bind_mm(struct intel_iommu *iommu,
>  	sflags = (flags & SVM_FLAG_SUPERVISOR_MODE) ?
>  			PASID_FLAG_SUPERVISOR_MODE : 0;
>  	sflags |= cpu_feature_enabled(X86_FEATURE_LA57) ? PASID_FLAG_FL5LP : 0;
> -	ret = intel_pasid_setup_first_level(iommu, dev, mm->pgd, mm->pasid,
> +
> +	pgd = static_cpu_has(X86_FEATURE_PTI) ? kernel_to_user_pgdp(mm->pgd) : mm->pgd;
> +	ret = intel_pasid_setup_first_level(iommu, dev, pgd, mm->pasid,
>  					    FLPT_DEFAULT_DID, sflags);

This X86_FEATURE_PTI should really be done within a helper.

I'd probably do this with a *new* helper since all of the existing
kernel_to_user_pgdp() users seem to be within a PTI #ifdef.

Maybe something like:

pgd_t *mm_user_pgd(struct mm_struct *mm)
{
#ifdef CONFIG_PAGE_TABLE_ISOLATION
	if (cpu_feature_enabled(X86_FEATURE_PTI))
		return kernel_to_user_pgdp(mm->pgd);
#endif
	return mm->pgd;
}

That #ifdef could even go away if your kernel_to_user_pgdp() stub from
patch 1/2 was available.  I'm not sure it's worth it though.
Re: [PATCH 2/2] iommu: Use the user PGD for SVA if PTI is enabled
Posted by Jacob Pan 3 years, 7 months ago
Hi Dave,

On Mon, 22 Aug 2022 15:31:20 -0700, Dave Hansen <dave.hansen@intel.com>
wrote:

> On 8/22/22 13:12, Jacob Pan wrote:
> > @@ -394,7 +395,9 @@ static struct iommu_sva *intel_svm_bind_mm(struct
> > intel_iommu *iommu, sflags = (flags & SVM_FLAG_SUPERVISOR_MODE) ?
> >  			PASID_FLAG_SUPERVISOR_MODE : 0;
> >  	sflags |= cpu_feature_enabled(X86_FEATURE_LA57) ?
> > PASID_FLAG_FL5LP : 0;
> > -	ret = intel_pasid_setup_first_level(iommu, dev, mm->pgd,
> > mm->pasid, +
> > +	pgd = static_cpu_has(X86_FEATURE_PTI) ?
> > kernel_to_user_pgdp(mm->pgd) : mm->pgd;
> > +	ret = intel_pasid_setup_first_level(iommu, dev, pgd, mm->pasid,
> >  					    FLPT_DEFAULT_DID, sflags);
> >  
> 
> This X86_FEATURE_PTI should really be done within a helper.
> 
> I'd probably do this with a *new* helper since all of the existing
> kernel_to_user_pgdp() users seem to be within a PTI #ifdef.
> 
> Maybe something like:
> 
> pgd_t *mm_user_pgd(struct mm_struct *mm)
> {
> #ifdef CONFIG_PAGE_TABLE_ISOLATION
> 	if (cpu_feature_enabled(X86_FEATURE_PTI))
> 		return kernel_to_user_pgdp(mm->pgd);
> #endif
> 	return mm->pgd;
> }
> 
Sounds good. I thought about a helper also, thinking there are so many other
cpu_has(X86_FEATURE_PTI) checks already :)

> That #ifdef could even go away if your kernel_to_user_pgdp() stub from
> patch 1/2 was available.  I'm not sure it's worth it though.
I will remove 1/2 and keep the uniform style of the existing helpers.

Thanks for the suggestion,

Jacob
Re: [PATCH 2/2] iommu: Use the user PGD for SVA if PTI is enabled
Posted by Dave Hansen 3 years, 7 months ago
On 8/22/22 16:24, Jacob Pan wrote:
> Sounds good. I thought about a helper also, thinking there are so many other
> cpu_has(X86_FEATURE_PTI) checks already :)

Yes, but almost all of those are in PTI-#ifdef'd code already.