Skip to content

Commit 23e5d9e

Browse files
kirylhansendc
authored andcommitted
x86/mm/iommu/sva: Make LAM and SVA mutually exclusive
IOMMU and SVA-capable devices know nothing about LAM and only expect canonical addresses. An attempt to pass down tagged pointer will lead to address translation failure. By default do not allow to enable both LAM and use SVA in the same process. The new ARCH_FORCE_TAGGED_SVA arch_prctl() overrides the limitation. By using the arch_prctl() userspace takes responsibility to never pass tagged address to the device. Signed-off-by: Kirill A. Shutemov <[email protected]> Signed-off-by: Dave Hansen <[email protected]> Reviewed-by: Ashok Raj <[email protected]> Reviewed-by: Jacob Pan <[email protected]> Acked-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lore.kernel.org/all/20230312112612.31869-12-kirill.shutemov%40linux.intel.com
1 parent 400b9b9 commit 23e5d9e

File tree

6 files changed

+27
-0
lines changed

6 files changed

+27
-0
lines changed

arch/x86/include/asm/mmu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#define MM_CONTEXT_HAS_VSYSCALL 1
1515
/* Do not allow changing LAM mode */
1616
#define MM_CONTEXT_LOCK_LAM 2
17+
/* Allow LAM and SVA coexisting */
18+
#define MM_CONTEXT_FORCE_TAGGED_SVA 3
1719

1820
/*
1921
* x86 has arch-specific MMU state beyond what lives in mm_struct.

arch/x86/include/asm/mmu_context.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ static inline void mm_reset_untag_mask(struct mm_struct *mm)
115115
mm->context.untag_mask = -1UL;
116116
}
117117

118+
#define arch_pgtable_dma_compat arch_pgtable_dma_compat
119+
static inline bool arch_pgtable_dma_compat(struct mm_struct *mm)
120+
{
121+
return !mm_lam_cr3_mask(mm) ||
122+
test_bit(MM_CONTEXT_FORCE_TAGGED_SVA, &mm->context.flags);
123+
}
118124
#else
119125

120126
static inline unsigned long mm_lam_cr3_mask(struct mm_struct *mm)

arch/x86/include/uapi/asm/prctl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@
2323
#define ARCH_GET_UNTAG_MASK 0x4001
2424
#define ARCH_ENABLE_TAGGED_ADDR 0x4002
2525
#define ARCH_GET_MAX_TAG_BITS 0x4003
26+
#define ARCH_FORCE_TAGGED_SVA 0x4004
2627

2728
#endif /* _ASM_X86_PRCTL_H */

arch/x86/kernel/process_64.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,10 @@ static int prctl_enable_tagged_addr(struct mm_struct *mm, unsigned long nr_bits)
756756
if (current->mm != mm)
757757
return -EINVAL;
758758

759+
if (mm_valid_pasid(mm) &&
760+
!test_bit(MM_CONTEXT_FORCE_TAGGED_SVA, &mm->context.flags))
761+
return -EINTR;
762+
759763
if (mmap_write_lock_killable(mm))
760764
return -EINTR;
761765

@@ -878,6 +882,9 @@ long do_arch_prctl_64(struct task_struct *task, int option, unsigned long arg2)
878882
(unsigned long __user *)arg2);
879883
case ARCH_ENABLE_TAGGED_ADDR:
880884
return prctl_enable_tagged_addr(task->mm, arg2);
885+
case ARCH_FORCE_TAGGED_SVA:
886+
set_bit(MM_CONTEXT_FORCE_TAGGED_SVA, &task->mm->context.flags);
887+
return 0;
881888
case ARCH_GET_MAX_TAG_BITS:
882889
if (!cpu_feature_enabled(X86_FEATURE_LAM))
883890
return put_user(0, (unsigned long __user *)arg2);

drivers/iommu/iommu-sva.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/*
33
* Helpers for IOMMU drivers implementing SVA
44
*/
5+
#include <linux/mmu_context.h>
56
#include <linux/mutex.h>
67
#include <linux/sched/mm.h>
78
#include <linux/iommu.h>
@@ -32,6 +33,9 @@ int iommu_sva_alloc_pasid(struct mm_struct *mm, ioasid_t min, ioasid_t max)
3233
min == 0 || max < min)
3334
return -EINVAL;
3435

36+
if (!arch_pgtable_dma_compat(mm))
37+
return -EBUSY;
38+
3539
mutex_lock(&iommu_sva_lock);
3640
/* Is a PASID already associated with this mm? */
3741
if (mm_valid_pasid(mm)) {

include/linux/mmu_context.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,11 @@ static inline unsigned long mm_untag_mask(struct mm_struct *mm)
3535
}
3636
#endif
3737

38+
#ifndef arch_pgtable_dma_compat
39+
static inline bool arch_pgtable_dma_compat(struct mm_struct *mm)
40+
{
41+
return true;
42+
}
43+
#endif
44+
3845
#endif

0 commit comments

Comments
 (0)