]>
Commit | Line | Data |
---|---|---|
59d5af67 | 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
321d628a FG |
2 | From: Andy Lutomirski <luto@kernel.org> |
3 | Date: Mon, 4 Dec 2017 15:07:15 +0100 | |
59d5af67 FG |
4 | Subject: [PATCH] x86/mm/fixmap: Generalize the GDT fixmap mechanism, introduce |
5 | struct cpu_entry_area | |
321d628a FG |
6 | MIME-Version: 1.0 |
7 | Content-Type: text/plain; charset=UTF-8 | |
8 | Content-Transfer-Encoding: 8bit | |
9 | ||
10 | CVE-2017-5754 | |
11 | ||
12 | Currently, the GDT is an ad-hoc array of pages, one per CPU, in the | |
13 | fixmap. Generalize it to be an array of a new 'struct cpu_entry_area' | |
14 | so that we can cleanly add new things to it. | |
15 | ||
16 | Signed-off-by: Andy Lutomirski <luto@kernel.org> | |
17 | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | |
18 | Reviewed-by: Thomas Gleixner <tglx@linutronix.de> | |
19 | Reviewed-by: Borislav Petkov <bp@suse.de> | |
20 | Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com> | |
21 | Cc: Borislav Petkov <bp@alien8.de> | |
22 | Cc: Borislav Petkov <bpetkov@suse.de> | |
23 | Cc: Brian Gerst <brgerst@gmail.com> | |
24 | Cc: Dave Hansen <dave.hansen@intel.com> | |
25 | Cc: Dave Hansen <dave.hansen@linux.intel.com> | |
26 | Cc: David Laight <David.Laight@aculab.com> | |
27 | Cc: Denys Vlasenko <dvlasenk@redhat.com> | |
28 | Cc: Eduardo Valentin <eduval@amazon.com> | |
29 | Cc: Greg KH <gregkh@linuxfoundation.org> | |
30 | Cc: H. Peter Anvin <hpa@zytor.com> | |
31 | Cc: Josh Poimboeuf <jpoimboe@redhat.com> | |
32 | Cc: Juergen Gross <jgross@suse.com> | |
33 | Cc: Linus Torvalds <torvalds@linux-foundation.org> | |
34 | Cc: Peter Zijlstra <peterz@infradead.org> | |
35 | Cc: Rik van Riel <riel@redhat.com> | |
36 | Cc: Will Deacon <will.deacon@arm.com> | |
37 | Cc: aliguori@amazon.com | |
38 | Cc: daniel.gruss@iaik.tugraz.at | |
39 | Cc: hughd@google.com | |
40 | Cc: keescook@google.com | |
41 | Link: https://lkml.kernel.org/r/20171204150605.563271721@linutronix.de | |
42 | Signed-off-by: Ingo Molnar <mingo@kernel.org> | |
43 | (cherry picked from commit ef8813ab280507972bb57e4b1b502811ad4411e9) | |
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 b17894f1ac91491ce29946ed946a129620b7f7ac) | |
47 | Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> | |
48 | --- | |
49 | arch/x86/include/asm/desc.h | 9 +-------- | |
50 | arch/x86/include/asm/fixmap.h | 37 +++++++++++++++++++++++++++++++++++-- | |
51 | arch/x86/kernel/cpu/common.c | 14 +++++++------- | |
52 | arch/x86/xen/mmu_pv.c | 2 +- | |
53 | 4 files changed, 44 insertions(+), 18 deletions(-) | |
54 | ||
55 | diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h | |
56 | index 22ee0a93b4f7..81c9b1e8cae9 100644 | |
57 | --- a/arch/x86/include/asm/desc.h | |
58 | +++ b/arch/x86/include/asm/desc.h | |
59 | @@ -58,17 +58,10 @@ static inline struct desc_struct *get_current_gdt_rw(void) | |
60 | return this_cpu_ptr(&gdt_page)->gdt; | |
61 | } | |
62 | ||
63 | -/* Get the fixmap index for a specific processor */ | |
64 | -static inline unsigned int get_cpu_gdt_ro_index(int cpu) | |
65 | -{ | |
66 | - return FIX_GDT_REMAP_END - cpu; | |
67 | -} | |
68 | - | |
69 | /* Provide the fixmap address of the remapped GDT */ | |
70 | static inline struct desc_struct *get_cpu_gdt_ro(int cpu) | |
71 | { | |
72 | - unsigned int idx = get_cpu_gdt_ro_index(cpu); | |
73 | - return (struct desc_struct *)__fix_to_virt(idx); | |
74 | + return (struct desc_struct *)&get_cpu_entry_area(cpu)->gdt; | |
75 | } | |
76 | ||
77 | /* Provide the current read-only GDT */ | |
78 | diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h | |
79 | index 81c2b11f50a6..8c6ed66fe957 100644 | |
80 | --- a/arch/x86/include/asm/fixmap.h | |
81 | +++ b/arch/x86/include/asm/fixmap.h | |
82 | @@ -44,6 +44,19 @@ extern unsigned long __FIXADDR_TOP; | |
83 | PAGE_SIZE) | |
84 | #endif | |
85 | ||
86 | +/* | |
87 | + * cpu_entry_area is a percpu region in the fixmap that contains things | |
88 | + * needed by the CPU and early entry/exit code. Real types aren't used | |
89 | + * for all fields here to avoid circular header dependencies. | |
90 | + * | |
91 | + * Every field is a virtual alias of some other allocated backing store. | |
92 | + * There is no direct allocation of a struct cpu_entry_area. | |
93 | + */ | |
94 | +struct cpu_entry_area { | |
95 | + char gdt[PAGE_SIZE]; | |
96 | +}; | |
97 | + | |
98 | +#define CPU_ENTRY_AREA_PAGES (sizeof(struct cpu_entry_area) / PAGE_SIZE) | |
99 | ||
100 | /* | |
101 | * Here we define all the compile-time 'special' virtual | |
102 | @@ -101,8 +114,8 @@ enum fixed_addresses { | |
103 | FIX_LNW_VRTC, | |
104 | #endif | |
105 | /* Fixmap entries to remap the GDTs, one per processor. */ | |
106 | - FIX_GDT_REMAP_BEGIN, | |
107 | - FIX_GDT_REMAP_END = FIX_GDT_REMAP_BEGIN + NR_CPUS - 1, | |
108 | + FIX_CPU_ENTRY_AREA_TOP, | |
109 | + FIX_CPU_ENTRY_AREA_BOTTOM = FIX_CPU_ENTRY_AREA_TOP + (CPU_ENTRY_AREA_PAGES * NR_CPUS) - 1, | |
110 | ||
111 | #ifdef CONFIG_ACPI_APEI_GHES | |
112 | /* Used for GHES mapping from assorted contexts */ | |
113 | @@ -171,5 +184,25 @@ static inline void __set_fixmap(enum fixed_addresses idx, | |
114 | void __early_set_fixmap(enum fixed_addresses idx, | |
115 | phys_addr_t phys, pgprot_t flags); | |
116 | ||
117 | +static inline unsigned int __get_cpu_entry_area_page_index(int cpu, int page) | |
118 | +{ | |
119 | + BUILD_BUG_ON(sizeof(struct cpu_entry_area) % PAGE_SIZE != 0); | |
120 | + | |
121 | + return FIX_CPU_ENTRY_AREA_BOTTOM - cpu*CPU_ENTRY_AREA_PAGES - page; | |
122 | +} | |
123 | + | |
124 | +#define __get_cpu_entry_area_offset_index(cpu, offset) ({ \ | |
125 | + BUILD_BUG_ON(offset % PAGE_SIZE != 0); \ | |
126 | + __get_cpu_entry_area_page_index(cpu, offset / PAGE_SIZE); \ | |
127 | + }) | |
128 | + | |
129 | +#define get_cpu_entry_area_index(cpu, field) \ | |
130 | + __get_cpu_entry_area_offset_index((cpu), offsetof(struct cpu_entry_area, field)) | |
131 | + | |
132 | +static inline struct cpu_entry_area *get_cpu_entry_area(int cpu) | |
133 | +{ | |
134 | + return (struct cpu_entry_area *)__fix_to_virt(__get_cpu_entry_area_page_index(cpu, 0)); | |
135 | +} | |
136 | + | |
137 | #endif /* !__ASSEMBLY__ */ | |
138 | #endif /* _ASM_X86_FIXMAP_H */ | |
139 | diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c | |
140 | index aa97e4cd3a33..ffee73ec1af1 100644 | |
141 | --- a/arch/x86/kernel/cpu/common.c | |
142 | +++ b/arch/x86/kernel/cpu/common.c | |
143 | @@ -466,12 +466,12 @@ void load_percpu_segment(int cpu) | |
144 | load_stack_canary_segment(); | |
145 | } | |
146 | ||
147 | -/* Setup the fixmap mapping only once per-processor */ | |
148 | -static inline void setup_fixmap_gdt(int cpu) | |
149 | +/* Setup the fixmap mappings only once per-processor */ | |
150 | +static inline void setup_cpu_entry_area(int cpu) | |
151 | { | |
152 | #ifdef CONFIG_X86_64 | |
153 | /* On 64-bit systems, we use a read-only fixmap GDT. */ | |
154 | - pgprot_t prot = PAGE_KERNEL_RO; | |
155 | + pgprot_t gdt_prot = PAGE_KERNEL_RO; | |
156 | #else | |
157 | /* | |
158 | * On native 32-bit systems, the GDT cannot be read-only because | |
159 | @@ -482,11 +482,11 @@ static inline void setup_fixmap_gdt(int cpu) | |
160 | * On Xen PV, the GDT must be read-only because the hypervisor requires | |
161 | * it. | |
162 | */ | |
163 | - pgprot_t prot = boot_cpu_has(X86_FEATURE_XENPV) ? | |
164 | + pgprot_t gdt_prot = boot_cpu_has(X86_FEATURE_XENPV) ? | |
165 | PAGE_KERNEL_RO : PAGE_KERNEL; | |
166 | #endif | |
167 | ||
168 | - __set_fixmap(get_cpu_gdt_ro_index(cpu), get_cpu_gdt_paddr(cpu), prot); | |
169 | + __set_fixmap(get_cpu_entry_area_index(cpu, gdt), get_cpu_gdt_paddr(cpu), gdt_prot); | |
170 | } | |
171 | ||
172 | /* Load the original GDT from the per-cpu structure */ | |
173 | @@ -1589,7 +1589,7 @@ void cpu_init(void) | |
174 | if (is_uv_system()) | |
175 | uv_cpu_init(); | |
176 | ||
177 | - setup_fixmap_gdt(cpu); | |
178 | + setup_cpu_entry_area(cpu); | |
179 | load_fixmap_gdt(cpu); | |
180 | } | |
181 | ||
182 | @@ -1650,7 +1650,7 @@ void cpu_init(void) | |
183 | ||
184 | fpu__init_cpu(); | |
185 | ||
186 | - setup_fixmap_gdt(cpu); | |
187 | + setup_cpu_entry_area(cpu); | |
188 | load_fixmap_gdt(cpu); | |
189 | } | |
190 | #endif | |
191 | diff --git a/arch/x86/xen/mmu_pv.c b/arch/x86/xen/mmu_pv.c | |
192 | index 45bb2d462e44..53e65f605bdd 100644 | |
193 | --- a/arch/x86/xen/mmu_pv.c | |
194 | +++ b/arch/x86/xen/mmu_pv.c | |
195 | @@ -2297,7 +2297,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot) | |
196 | #endif | |
197 | case FIX_TEXT_POKE0: | |
198 | case FIX_TEXT_POKE1: | |
199 | - case FIX_GDT_REMAP_BEGIN ... FIX_GDT_REMAP_END: | |
200 | + case FIX_CPU_ENTRY_AREA_TOP ... FIX_CPU_ENTRY_AREA_BOTTOM: | |
201 | /* All local page mappings */ | |
202 | pte = pfn_pte(phys, prot); | |
203 | break; | |
204 | -- | |
205 | 2.14.2 | |
206 |