]>
Commit | Line | Data |
---|---|---|
321d628a FG |
1 | From 39f179e9baa1728a99a60c5933b1a4a3db73e617 Mon Sep 17 00:00:00 2001 |
2 | From: Dave Hansen <dave.hansen@linux.intel.com> | |
3 | Date: Mon, 4 Dec 2017 15:07:39 +0100 | |
7c7389df | 4 | Subject: [PATCH 194/232] x86/mm/pti: Allocate a separate user PGD |
321d628a FG |
5 | MIME-Version: 1.0 |
6 | Content-Type: text/plain; charset=UTF-8 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ||
9 | CVE-2017-5754 | |
10 | ||
11 | Kernel page table isolation requires to have two PGDs. One for the kernel, | |
12 | which contains the full kernel mapping plus the user space mapping and one | |
13 | for user space which contains the user space mappings and the minimal set | |
14 | of kernel mappings which are required by the architecture to be able to | |
15 | transition from and to user space. | |
16 | ||
17 | Add the necessary preliminaries. | |
18 | ||
19 | [ tglx: Split out from the big kaiser dump. EFI fixup from Kirill ] | |
20 | ||
21 | Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> | |
22 | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | |
23 | Reviewed-by: Borislav Petkov <bp@suse.de> | |
24 | Cc: Andy Lutomirski <luto@kernel.org> | |
25 | Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com> | |
26 | Cc: Borislav Petkov <bp@alien8.de> | |
27 | Cc: Brian Gerst <brgerst@gmail.com> | |
28 | Cc: David Laight <David.Laight@aculab.com> | |
29 | Cc: Denys Vlasenko <dvlasenk@redhat.com> | |
30 | Cc: Eduardo Valentin <eduval@amazon.com> | |
31 | Cc: Greg KH <gregkh@linuxfoundation.org> | |
32 | Cc: H. Peter Anvin <hpa@zytor.com> | |
33 | Cc: Josh Poimboeuf <jpoimboe@redhat.com> | |
34 | Cc: Juergen Gross <jgross@suse.com> | |
35 | Cc: Linus Torvalds <torvalds@linux-foundation.org> | |
36 | Cc: Peter Zijlstra <peterz@infradead.org> | |
37 | Cc: Will Deacon <will.deacon@arm.com> | |
38 | Cc: aliguori@amazon.com | |
39 | Cc: daniel.gruss@iaik.tugraz.at | |
40 | Cc: hughd@google.com | |
41 | Cc: keescook@google.com | |
42 | Signed-off-by: Ingo Molnar <mingo@kernel.org> | |
43 | (backported from commit d9e9a6418065bb376e5de8d93ce346939b9a37a6) | |
44 | Signed-off-by: Andy Whitcroft <apw@canonical.com> | |
45 | Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com> | |
46 | (cherry picked from commit 0bd4b34e330d8bedf90c0497dfcef2e2286c4367) | |
47 | Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> | |
48 | --- | |
49 | arch/x86/include/asm/pgalloc.h | 11 +++++++++++ | |
50 | arch/x86/mm/pgtable.c | 5 +++-- | |
51 | arch/x86/platform/efi/efi_64.c | 5 ++++- | |
52 | arch/x86/kernel/head_64.S | 30 +++++++++++++++++++++++++++--- | |
53 | 4 files changed, 45 insertions(+), 6 deletions(-) | |
54 | ||
55 | diff --git a/arch/x86/include/asm/pgalloc.h b/arch/x86/include/asm/pgalloc.h | |
56 | index b2d0cd8288aa..d65b0dee7448 100644 | |
57 | --- a/arch/x86/include/asm/pgalloc.h | |
58 | +++ b/arch/x86/include/asm/pgalloc.h | |
59 | @@ -29,6 +29,17 @@ static inline void paravirt_release_p4d(unsigned long pfn) {} | |
60 | */ | |
61 | extern gfp_t __userpte_alloc_gfp; | |
62 | ||
63 | +#ifdef CONFIG_PAGE_TABLE_ISOLATION | |
64 | +/* | |
65 | + * Instead of one PGD, we acquire two PGDs. Being order-1, it is | |
66 | + * both 8k in size and 8k-aligned. That lets us just flip bit 12 | |
67 | + * in a pointer to swap between the two 4k halves. | |
68 | + */ | |
69 | +#define PGD_ALLOCATION_ORDER 1 | |
70 | +#else | |
71 | +#define PGD_ALLOCATION_ORDER 0 | |
72 | +#endif | |
73 | + | |
74 | /* | |
75 | * Allocate and free page tables. | |
76 | */ | |
77 | diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c | |
78 | index 942391b5b639..90d1d8f49cf6 100644 | |
79 | --- a/arch/x86/mm/pgtable.c | |
80 | +++ b/arch/x86/mm/pgtable.c | |
81 | @@ -354,14 +354,15 @@ static inline void _pgd_free(pgd_t *pgd) | |
82 | kmem_cache_free(pgd_cache, pgd); | |
83 | } | |
84 | #else | |
85 | + | |
86 | static inline pgd_t *_pgd_alloc(void) | |
87 | { | |
88 | - return (pgd_t *)__get_free_page(PGALLOC_GFP); | |
89 | + return (pgd_t *)__get_free_pages(PGALLOC_GFP, PGD_ALLOCATION_ORDER); | |
90 | } | |
91 | ||
92 | static inline void _pgd_free(pgd_t *pgd) | |
93 | { | |
94 | - free_page((unsigned long)pgd); | |
95 | + free_pages((unsigned long)pgd, PGD_ALLOCATION_ORDER); | |
96 | } | |
97 | #endif /* CONFIG_X86_PAE */ | |
98 | ||
99 | diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c | |
100 | index 9bf72f5bfedb..b104224d3d6c 100644 | |
101 | --- a/arch/x86/platform/efi/efi_64.c | |
102 | +++ b/arch/x86/platform/efi/efi_64.c | |
103 | @@ -194,6 +194,9 @@ static pgd_t *efi_pgd; | |
104 | * because we want to avoid inserting EFI region mappings (EFI_VA_END | |
105 | * to EFI_VA_START) into the standard kernel page tables. Everything | |
106 | * else can be shared, see efi_sync_low_kernel_mappings(). | |
107 | + * | |
108 | + * We don't want the pgd on the pgd_list and cannot use pgd_alloc() for the | |
109 | + * allocation. | |
110 | */ | |
111 | int __init efi_alloc_page_tables(void) | |
112 | { | |
113 | @@ -206,7 +209,7 @@ int __init efi_alloc_page_tables(void) | |
114 | return 0; | |
115 | ||
116 | gfp_mask = GFP_KERNEL | __GFP_NOTRACK | __GFP_ZERO; | |
117 | - efi_pgd = (pgd_t *)__get_free_page(gfp_mask); | |
118 | + efi_pgd = (pgd_t *)__get_free_pages(gfp_mask, PGD_ALLOCATION_ORDER); | |
119 | if (!efi_pgd) | |
120 | return -ENOMEM; | |
121 | ||
122 | diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S | |
123 | index e785734980ad..eeaaaab54b2a 100644 | |
124 | --- a/arch/x86/kernel/head_64.S | |
125 | +++ b/arch/x86/kernel/head_64.S | |
126 | @@ -324,6 +324,27 @@ GLOBAL(early_recursion_flag) | |
127 | .balign PAGE_SIZE; \ | |
128 | GLOBAL(name) | |
129 | ||
130 | +#ifdef CONFIG_PAGE_TABLE_ISOLATION | |
131 | +/* | |
132 | + * Each PGD needs to be 8k long and 8k aligned. We do not | |
133 | + * ever go out to userspace with these, so we do not | |
134 | + * strictly *need* the second page, but this allows us to | |
135 | + * have a single set_pgd() implementation that does not | |
136 | + * need to worry about whether it has 4k or 8k to work | |
137 | + * with. | |
138 | + * | |
139 | + * This ensures PGDs are 8k long: | |
140 | + */ | |
141 | +#define PTI_USER_PGD_FILL 512 | |
142 | +/* This ensures they are 8k-aligned: */ | |
143 | +#define NEXT_PGD_PAGE(name) \ | |
144 | + .balign 2 * PAGE_SIZE; \ | |
145 | +GLOBAL(name) | |
146 | +#else | |
147 | +#define NEXT_PGD_PAGE(name) NEXT_PAGE(name) | |
148 | +#define PTI_USER_PGD_FILL 0 | |
149 | +#endif | |
150 | + | |
151 | /* Automate the creation of 1 to 1 mapping pmd entries */ | |
152 | #define PMDS(START, PERM, COUNT) \ | |
153 | i = 0 ; \ | |
154 | @@ -333,13 +354,14 @@ GLOBAL(name) | |
155 | .endr | |
156 | ||
157 | __INITDATA | |
158 | -NEXT_PAGE(early_top_pgt) | |
159 | +NEXT_PGD_PAGE(early_top_pgt) | |
160 | .fill 511,8,0 | |
161 | #ifdef CONFIG_X86_5LEVEL | |
162 | .quad level4_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE | |
163 | #else | |
164 | .quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE | |
165 | #endif | |
166 | + .fill PTI_USER_PGD_FILL,8,0 | |
167 | ||
168 | NEXT_PAGE(early_dynamic_pgts) | |
169 | .fill 512*EARLY_DYNAMIC_PAGE_TABLES,8,0 | |
170 | @@ -347,13 +369,14 @@ NEXT_PAGE(early_dynamic_pgts) | |
171 | .data | |
172 | ||
173 | #if defined(CONFIG_XEN_PV) || defined(CONFIG_XEN_PVH) | |
174 | -NEXT_PAGE(init_top_pgt) | |
175 | +NEXT_PGD_PAGE(init_top_pgt) | |
176 | .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE | |
177 | .org init_top_pgt + PGD_PAGE_OFFSET*8, 0 | |
178 | .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE | |
179 | .org init_top_pgt + PGD_START_KERNEL*8, 0 | |
180 | /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */ | |
181 | .quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE | |
182 | + .fill PTI_USER_PGD_FILL,8,0 | |
183 | ||
184 | NEXT_PAGE(level3_ident_pgt) | |
185 | .quad level2_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE | |
186 | @@ -364,8 +387,9 @@ NEXT_PAGE(level2_ident_pgt) | |
187 | */ | |
188 | PMDS(0, __PAGE_KERNEL_IDENT_LARGE_EXEC, PTRS_PER_PMD) | |
189 | #else | |
190 | -NEXT_PAGE(init_top_pgt) | |
191 | +NEXT_PGD_PAGE(init_top_pgt) | |
192 | .fill 512,8,0 | |
193 | + .fill PTI_USER_PGD_FILL,8,0 | |
194 | #endif | |
195 | ||
196 | #ifdef CONFIG_X86_5LEVEL | |
197 | -- | |
198 | 2.14.2 | |
199 |