]>
Commit | Line | Data |
---|---|---|
321d628a FG |
1 | From 3868ecbc68a9713951f3008ef3af3b9da7e67e60 Mon Sep 17 00:00:00 2001 |
2 | From: Andy Lutomirski <luto@kernel.org> | |
3 | Date: Thu, 2 Nov 2017 00:59:10 -0700 | |
b378f209 | 4 | Subject: [PATCH 098/233] x86/entry/64: Pass SP0 directly to load_sp0() |
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 | load_sp0() had an odd signature: | |
12 | ||
13 | void load_sp0(struct tss_struct *tss, struct thread_struct *thread); | |
14 | ||
15 | Simplify it to: | |
16 | ||
17 | void load_sp0(unsigned long sp0); | |
18 | ||
19 | Also simplify a few get_cpu()/put_cpu() sequences to | |
20 | preempt_disable()/preempt_enable(). | |
21 | ||
22 | Signed-off-by: Andy Lutomirski <luto@kernel.org> | |
23 | Reviewed-by: Borislav Petkov <bp@suse.de> | |
24 | Cc: Borislav Petkov <bpetkov@suse.de> | |
25 | Cc: Brian Gerst <brgerst@gmail.com> | |
26 | Cc: Dave Hansen <dave.hansen@intel.com> | |
27 | Cc: Linus Torvalds <torvalds@linux-foundation.org> | |
28 | Cc: Peter Zijlstra <peterz@infradead.org> | |
29 | Cc: Thomas Gleixner <tglx@linutronix.de> | |
30 | Link: http://lkml.kernel.org/r/2655d8b42ed940aa384fe18ee1129bbbcf730a08.1509609304.git.luto@kernel.org | |
31 | Signed-off-by: Ingo Molnar <mingo@kernel.org> | |
32 | (cherry picked from commit da51da189a24bb9b7e2d5a123be096e51a4695a5) | |
33 | Signed-off-by: Andy Whitcroft <apw@canonical.com> | |
34 | Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com> | |
35 | (cherry picked from commit 41f6a89b0be4d052a6af59df5e56102d4e4c79ef) | |
36 | Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com> | |
37 | --- | |
38 | arch/x86/include/asm/paravirt.h | 5 ++--- | |
39 | arch/x86/include/asm/paravirt_types.h | 2 +- | |
40 | arch/x86/include/asm/processor.h | 9 ++++----- | |
41 | arch/x86/kernel/cpu/common.c | 4 ++-- | |
42 | arch/x86/kernel/process_32.c | 2 +- | |
43 | arch/x86/kernel/process_64.c | 2 +- | |
44 | arch/x86/kernel/vm86_32.c | 14 ++++++-------- | |
45 | arch/x86/xen/enlighten_pv.c | 7 +++---- | |
46 | 8 files changed, 20 insertions(+), 25 deletions(-) | |
47 | ||
48 | diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h | |
49 | index 12deec722cf0..43d4f90edebc 100644 | |
50 | --- a/arch/x86/include/asm/paravirt.h | |
51 | +++ b/arch/x86/include/asm/paravirt.h | |
52 | @@ -15,10 +15,9 @@ | |
53 | #include <linux/cpumask.h> | |
54 | #include <asm/frame.h> | |
55 | ||
56 | -static inline void load_sp0(struct tss_struct *tss, | |
57 | - struct thread_struct *thread) | |
58 | +static inline void load_sp0(unsigned long sp0) | |
59 | { | |
60 | - PVOP_VCALL2(pv_cpu_ops.load_sp0, tss, thread); | |
61 | + PVOP_VCALL1(pv_cpu_ops.load_sp0, sp0); | |
62 | } | |
63 | ||
64 | /* The paravirtualized CPUID instruction. */ | |
65 | diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h | |
66 | index 42873edd9f9d..e3953a1e2b57 100644 | |
67 | --- a/arch/x86/include/asm/paravirt_types.h | |
68 | +++ b/arch/x86/include/asm/paravirt_types.h | |
69 | @@ -133,7 +133,7 @@ struct pv_cpu_ops { | |
70 | void (*alloc_ldt)(struct desc_struct *ldt, unsigned entries); | |
71 | void (*free_ldt)(struct desc_struct *ldt, unsigned entries); | |
72 | ||
73 | - void (*load_sp0)(struct tss_struct *tss, struct thread_struct *t); | |
74 | + void (*load_sp0)(unsigned long sp0); | |
75 | ||
76 | void (*set_iopl_mask)(unsigned mask); | |
77 | ||
78 | diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h | |
79 | index ee37fb86900a..85ddfc1a9bb5 100644 | |
80 | --- a/arch/x86/include/asm/processor.h | |
81 | +++ b/arch/x86/include/asm/processor.h | |
82 | @@ -510,9 +510,9 @@ static inline void native_set_iopl_mask(unsigned mask) | |
83 | } | |
84 | ||
85 | static inline void | |
86 | -native_load_sp0(struct tss_struct *tss, struct thread_struct *thread) | |
87 | +native_load_sp0(unsigned long sp0) | |
88 | { | |
89 | - tss->x86_tss.sp0 = thread->sp0; | |
90 | + this_cpu_write(cpu_tss.x86_tss.sp0, sp0); | |
91 | } | |
92 | ||
93 | static inline void native_swapgs(void) | |
94 | @@ -537,10 +537,9 @@ static inline unsigned long current_top_of_stack(void) | |
95 | #else | |
96 | #define __cpuid native_cpuid | |
97 | ||
98 | -static inline void load_sp0(struct tss_struct *tss, | |
99 | - struct thread_struct *thread) | |
100 | +static inline void load_sp0(unsigned long sp0) | |
101 | { | |
102 | - native_load_sp0(tss, thread); | |
103 | + native_load_sp0(sp0); | |
104 | } | |
105 | ||
106 | #define set_iopl_mask native_set_iopl_mask | |
107 | diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c | |
108 | index ef7b1ba56363..6562acbfc4e0 100644 | |
109 | --- a/arch/x86/kernel/cpu/common.c | |
110 | +++ b/arch/x86/kernel/cpu/common.c | |
111 | @@ -1570,7 +1570,7 @@ void cpu_init(void) | |
112 | BUG_ON(me->mm); | |
113 | enter_lazy_tlb(&init_mm, me); | |
114 | ||
115 | - load_sp0(t, ¤t->thread); | |
116 | + load_sp0(current->thread.sp0); | |
117 | set_tss_desc(cpu, t); | |
118 | load_TR_desc(); | |
119 | load_mm_ldt(&init_mm); | |
120 | @@ -1624,7 +1624,7 @@ void cpu_init(void) | |
121 | BUG_ON(curr->mm); | |
122 | enter_lazy_tlb(&init_mm, curr); | |
123 | ||
124 | - load_sp0(t, thread); | |
125 | + load_sp0(thread->sp0); | |
126 | set_tss_desc(cpu, t); | |
127 | load_TR_desc(); | |
128 | load_mm_ldt(&init_mm); | |
129 | diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c | |
130 | index 2e42b66b8ca4..48a3f240f565 100644 | |
131 | --- a/arch/x86/kernel/process_32.c | |
132 | +++ b/arch/x86/kernel/process_32.c | |
133 | @@ -287,7 +287,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) | |
134 | * current_thread_info(). Refresh the SYSENTER configuration in | |
135 | * case prev or next is vm86. | |
136 | */ | |
137 | - load_sp0(tss, next); | |
138 | + load_sp0(next->sp0); | |
139 | refresh_sysenter_cs(next); | |
140 | this_cpu_write(cpu_current_top_of_stack, | |
141 | (unsigned long)task_stack_page(next_p) + | |
142 | diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c | |
143 | index 565daaa6f18d..37b933628a8b 100644 | |
144 | --- a/arch/x86/kernel/process_64.c | |
145 | +++ b/arch/x86/kernel/process_64.c | |
146 | @@ -466,7 +466,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) | |
147 | this_cpu_write(current_task, next_p); | |
148 | ||
149 | /* Reload sp0. */ | |
150 | - load_sp0(tss, next); | |
151 | + load_sp0(next->sp0); | |
152 | ||
153 | /* | |
154 | * Now maybe reload the debug registers and handle I/O bitmaps | |
155 | diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c | |
156 | index 5bc1c3ab6287..0f1d92cd20ad 100644 | |
157 | --- a/arch/x86/kernel/vm86_32.c | |
158 | +++ b/arch/x86/kernel/vm86_32.c | |
159 | @@ -94,7 +94,6 @@ | |
160 | ||
161 | void save_v86_state(struct kernel_vm86_regs *regs, int retval) | |
162 | { | |
163 | - struct tss_struct *tss; | |
164 | struct task_struct *tsk = current; | |
165 | struct vm86plus_struct __user *user; | |
166 | struct vm86 *vm86 = current->thread.vm86; | |
167 | @@ -146,13 +145,13 @@ void save_v86_state(struct kernel_vm86_regs *regs, int retval) | |
168 | do_exit(SIGSEGV); | |
169 | } | |
170 | ||
171 | - tss = &per_cpu(cpu_tss, get_cpu()); | |
172 | + preempt_disable(); | |
173 | tsk->thread.sp0 = vm86->saved_sp0; | |
174 | tsk->thread.sysenter_cs = __KERNEL_CS; | |
175 | - load_sp0(tss, &tsk->thread); | |
176 | + load_sp0(tsk->thread.sp0); | |
177 | refresh_sysenter_cs(&tsk->thread); | |
178 | vm86->saved_sp0 = 0; | |
179 | - put_cpu(); | |
180 | + preempt_enable(); | |
181 | ||
182 | memcpy(®s->pt, &vm86->regs32, sizeof(struct pt_regs)); | |
183 | ||
184 | @@ -238,7 +237,6 @@ SYSCALL_DEFINE2(vm86, unsigned long, cmd, unsigned long, arg) | |
185 | ||
186 | static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus) | |
187 | { | |
188 | - struct tss_struct *tss; | |
189 | struct task_struct *tsk = current; | |
190 | struct vm86 *vm86 = tsk->thread.vm86; | |
191 | struct kernel_vm86_regs vm86regs; | |
192 | @@ -366,8 +364,8 @@ static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus) | |
193 | vm86->saved_sp0 = tsk->thread.sp0; | |
194 | lazy_save_gs(vm86->regs32.gs); | |
195 | ||
196 | - tss = &per_cpu(cpu_tss, get_cpu()); | |
197 | /* make room for real-mode segments */ | |
198 | + preempt_disable(); | |
199 | tsk->thread.sp0 += 16; | |
200 | ||
201 | if (static_cpu_has(X86_FEATURE_SEP)) { | |
202 | @@ -375,8 +373,8 @@ static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus) | |
203 | refresh_sysenter_cs(&tsk->thread); | |
204 | } | |
205 | ||
206 | - load_sp0(tss, &tsk->thread); | |
207 | - put_cpu(); | |
208 | + load_sp0(tsk->thread.sp0); | |
209 | + preempt_enable(); | |
210 | ||
211 | if (vm86->flags & VM86_SCREEN_BITMAP) | |
212 | mark_screen_rdonly(tsk->mm); | |
213 | diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c | |
214 | index 8da4eff19c2a..e7b213047724 100644 | |
215 | --- a/arch/x86/xen/enlighten_pv.c | |
216 | +++ b/arch/x86/xen/enlighten_pv.c | |
217 | @@ -810,15 +810,14 @@ static void __init xen_write_gdt_entry_boot(struct desc_struct *dt, int entry, | |
218 | } | |
219 | } | |
220 | ||
221 | -static void xen_load_sp0(struct tss_struct *tss, | |
222 | - struct thread_struct *thread) | |
223 | +static void xen_load_sp0(unsigned long sp0) | |
224 | { | |
225 | struct multicall_space mcs; | |
226 | ||
227 | mcs = xen_mc_entry(0); | |
228 | - MULTI_stack_switch(mcs.mc, __KERNEL_DS, thread->sp0); | |
229 | + MULTI_stack_switch(mcs.mc, __KERNEL_DS, sp0); | |
230 | xen_mc_issue(PARAVIRT_LAZY_CPU); | |
231 | - tss->x86_tss.sp0 = thread->sp0; | |
232 | + this_cpu_write(cpu_tss.x86_tss.sp0, sp0); | |
233 | } | |
234 | ||
235 | void xen_set_iopl_mask(unsigned mask) | |
236 | -- | |
237 | 2.14.2 | |
238 |