diff options
author | Qiaowei Ren <qiaowei.ren@intel.com> | 2014-11-14 10:18:27 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2014-11-17 18:58:53 -0500 |
commit | 57319d80e1d328e34cb24868a4f4405661485e30 (patch) | |
tree | bf8d64fe730c72f9e52717cc7ff7389aa44ba209 | |
parent | 4aae7e436fa51faf4bf5d11b175aea82cfe8224a (diff) |
x86, mpx: Add MPX-specific mmap interface
We have chosen to perform the allocation of bounds tables in
kernel (See the patch "on-demand kernel allocation of bounds
tables") and to mark these VMAs with VM_MPX.
However, there is currently no suitable interface to actually do
this. Existing interfaces, like do_mmap_pgoff(), have no way to
set a modified ->vm_ops or ->vm_flags and don't hold mmap_sem
long enough to let a caller do it.
This patch wraps mmap_region() and hold mmap_sem long enough to
make the modifications to the VMA which we need.
Also note the 32/64-bit #ifdef in the header. We actually need
to do this at runtime eventually. But, for now, we don't support
running 32-bit binaries on 64-bit kernels. Support for this will
come in later patches.
Signed-off-by: Qiaowei Ren <qiaowei.ren@intel.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Cc: linux-mm@kvack.org
Cc: linux-mips@linux-mips.org
Cc: Dave Hansen <dave@sr71.net>
Link: http://lkml.kernel.org/r/20141114151827.CE440F67@viggo.jf.intel.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | arch/x86/Kconfig | 4 | ||||
-rw-r--r-- | arch/x86/include/asm/mpx.h | 36 | ||||
-rw-r--r-- | arch/x86/mm/Makefile | 2 | ||||
-rw-r--r-- | arch/x86/mm/mpx.c | 86 |
4 files changed, 128 insertions, 0 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index ded8a6774ac9..967dfe0ba85e 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -248,6 +248,10 @@ config HAVE_INTEL_TXT | |||
248 | def_bool y | 248 | def_bool y |
249 | depends on INTEL_IOMMU && ACPI | 249 | depends on INTEL_IOMMU && ACPI |
250 | 250 | ||
251 | config X86_INTEL_MPX | ||
252 | def_bool y | ||
253 | depends on CPU_SUP_INTEL | ||
254 | |||
251 | config X86_32_SMP | 255 | config X86_32_SMP |
252 | def_bool y | 256 | def_bool y |
253 | depends on X86_32 && SMP | 257 | depends on X86_32 && SMP |
diff --git a/arch/x86/include/asm/mpx.h b/arch/x86/include/asm/mpx.h new file mode 100644 index 000000000000..7d7c5f54cc5f --- /dev/null +++ b/arch/x86/include/asm/mpx.h | |||
@@ -0,0 +1,36 @@ | |||
1 | #ifndef _ASM_X86_MPX_H | ||
2 | #define _ASM_X86_MPX_H | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | #include <asm/ptrace.h> | ||
6 | |||
7 | #ifdef CONFIG_X86_64 | ||
8 | |||
9 | /* upper 28 bits [47:20] of the virtual address in 64-bit used to | ||
10 | * index into bounds directory (BD). | ||
11 | */ | ||
12 | #define MPX_BD_ENTRY_OFFSET 28 | ||
13 | #define MPX_BD_ENTRY_SHIFT 3 | ||
14 | /* bits [19:3] of the virtual address in 64-bit used to index into | ||
15 | * bounds table (BT). | ||
16 | */ | ||
17 | #define MPX_BT_ENTRY_OFFSET 17 | ||
18 | #define MPX_BT_ENTRY_SHIFT 5 | ||
19 | #define MPX_IGN_BITS 3 | ||
20 | |||
21 | #else | ||
22 | |||
23 | #define MPX_BD_ENTRY_OFFSET 20 | ||
24 | #define MPX_BD_ENTRY_SHIFT 2 | ||
25 | #define MPX_BT_ENTRY_OFFSET 10 | ||
26 | #define MPX_BT_ENTRY_SHIFT 4 | ||
27 | #define MPX_IGN_BITS 2 | ||
28 | |||
29 | #endif | ||
30 | |||
31 | #define MPX_BD_SIZE_BYTES (1UL<<(MPX_BD_ENTRY_OFFSET+MPX_BD_ENTRY_SHIFT)) | ||
32 | #define MPX_BT_SIZE_BYTES (1UL<<(MPX_BT_ENTRY_OFFSET+MPX_BT_ENTRY_SHIFT)) | ||
33 | |||
34 | #define MPX_BNDSTA_ERROR_CODE 0x3 | ||
35 | |||
36 | #endif /* _ASM_X86_MPX_H */ | ||
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile index 6a19ad9f370d..ecfdc46a024a 100644 --- a/arch/x86/mm/Makefile +++ b/arch/x86/mm/Makefile | |||
@@ -30,3 +30,5 @@ obj-$(CONFIG_ACPI_NUMA) += srat.o | |||
30 | obj-$(CONFIG_NUMA_EMU) += numa_emulation.o | 30 | obj-$(CONFIG_NUMA_EMU) += numa_emulation.o |
31 | 31 | ||
32 | obj-$(CONFIG_MEMTEST) += memtest.o | 32 | obj-$(CONFIG_MEMTEST) += memtest.o |
33 | |||
34 | obj-$(CONFIG_X86_INTEL_MPX) += mpx.o | ||
diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c new file mode 100644 index 000000000000..72d13b0779a2 --- /dev/null +++ b/arch/x86/mm/mpx.c | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | * mpx.c - Memory Protection eXtensions | ||
3 | * | ||
4 | * Copyright (c) 2014, Intel Corporation. | ||
5 | * Qiaowei Ren <qiaowei.ren@intel.com> | ||
6 | * Dave Hansen <dave.hansen@intel.com> | ||
7 | */ | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/syscalls.h> | ||
10 | #include <linux/sched/sysctl.h> | ||
11 | |||
12 | #include <asm/mman.h> | ||
13 | #include <asm/mpx.h> | ||
14 | |||
15 | static const char *mpx_mapping_name(struct vm_area_struct *vma) | ||
16 | { | ||
17 | return "[mpx]"; | ||
18 | } | ||
19 | |||
20 | static struct vm_operations_struct mpx_vma_ops = { | ||
21 | .name = mpx_mapping_name, | ||
22 | }; | ||
23 | |||
24 | /* | ||
25 | * This is really a simplified "vm_mmap". it only handles MPX | ||
26 | * bounds tables (the bounds directory is user-allocated). | ||
27 | * | ||
28 | * Later on, we use the vma->vm_ops to uniquely identify these | ||
29 | * VMAs. | ||
30 | */ | ||
31 | static unsigned long mpx_mmap(unsigned long len) | ||
32 | { | ||
33 | unsigned long ret; | ||
34 | unsigned long addr, pgoff; | ||
35 | struct mm_struct *mm = current->mm; | ||
36 | vm_flags_t vm_flags; | ||
37 | struct vm_area_struct *vma; | ||
38 | |||
39 | /* Only bounds table and bounds directory can be allocated here */ | ||
40 | if (len != MPX_BD_SIZE_BYTES && len != MPX_BT_SIZE_BYTES) | ||
41 | return -EINVAL; | ||
42 | |||
43 | down_write(&mm->mmap_sem); | ||
44 | |||
45 | /* Too many mappings? */ | ||
46 | if (mm->map_count > sysctl_max_map_count) { | ||
47 | ret = -ENOMEM; | ||
48 | goto out; | ||
49 | } | ||
50 | |||
51 | /* Obtain the address to map to. we verify (or select) it and ensure | ||
52 | * that it represents a valid section of the address space. | ||
53 | */ | ||
54 | addr = get_unmapped_area(NULL, 0, len, 0, MAP_ANONYMOUS | MAP_PRIVATE); | ||
55 | if (addr & ~PAGE_MASK) { | ||
56 | ret = addr; | ||
57 | goto out; | ||
58 | } | ||
59 | |||
60 | vm_flags = VM_READ | VM_WRITE | VM_MPX | | ||
61 | mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; | ||
62 | |||
63 | /* Set pgoff according to addr for anon_vma */ | ||
64 | pgoff = addr >> PAGE_SHIFT; | ||
65 | |||
66 | ret = mmap_region(NULL, addr, len, vm_flags, pgoff); | ||
67 | if (IS_ERR_VALUE(ret)) | ||
68 | goto out; | ||
69 | |||
70 | vma = find_vma(mm, ret); | ||
71 | if (!vma) { | ||
72 | ret = -ENOMEM; | ||
73 | goto out; | ||
74 | } | ||
75 | vma->vm_ops = &mpx_vma_ops; | ||
76 | |||
77 | if (vm_flags & VM_LOCKED) { | ||
78 | up_write(&mm->mmap_sem); | ||
79 | mm_populate(ret, len); | ||
80 | return ret; | ||
81 | } | ||
82 | |||
83 | out: | ||
84 | up_write(&mm->mmap_sem); | ||
85 | return ret; | ||
86 | } | ||