summaryrefslogtreecommitdiffstats
path: root/arch/x86/power
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@kernel.org>2017-11-30 10:57:57 -0500
committerIngo Molnar <mingo@kernel.org>2017-12-06 06:29:12 -0500
commit5b06bbcfc2c621da3009da8decb7511500c293ed (patch)
treeb9f1c36dac098579ad53feb971b6225fcb48aaee /arch/x86/power
parentddec3bdee05b06f1dda20ded003c3e10e4184cab (diff)
x86/power: Fix some ordering bugs in __restore_processor_context()
__restore_processor_context() had a couple of ordering bugs. It restored GSBASE after calling load_gs_index(), and the latter can call into tracing code. It also tried to restore segment registers before restoring the LDT, which is straight-up wrong. Reorder the code so that we restore GSBASE, then the descriptor tables, then the segments. This fixes two bugs. First, it fixes a regression that broke resume under certain configurations due to irqflag tracing in native_load_gs_index(). Second, it fixes resume when the userspace process that initiated suspect had funny segments. The latter can be reproduced by compiling this: // SPDX-License-Identifier: GPL-2.0 /* * ldt_echo.c - Echo argv[1] while using an LDT segment */ int main(int argc, char **argv) { int ret; size_t len; char *buf; const struct user_desc desc = { .entry_number = 0, .base_addr = 0, .limit = 0xfffff, .seg_32bit = 1, .contents = 0, /* Data, grow-up */ .read_exec_only = 0, .limit_in_pages = 1, .seg_not_present = 0, .useable = 0 }; if (argc != 2) errx(1, "Usage: %s STRING", argv[0]); len = asprintf(&buf, "%s\n", argv[1]); if (len < 0) errx(1, "Out of memory"); ret = syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)); if (ret < -1) errno = -ret; if (ret) err(1, "modify_ldt"); asm volatile ("movw %0, %%es" :: "rm" ((unsigned short)7)); write(1, buf, len); return 0; } and running ldt_echo >/sys/power/mem Without the fix, the latter causes a triple fault on resume. Fixes: ca37e57bbe0c ("x86/entry/64: Add missing irqflags tracing to native_load_gs_index()") Reported-by: Jarkko Nikula <jarkko.nikula@linux.intel.com> Signed-off-by: Andy Lutomirski <luto@kernel.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Jarkko Nikula <jarkko.nikula@linux.intel.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Borislav Petkov <bp@alien8.de> Cc: Linus Torvalds <torvalds@linux-foundation.org> Link: https://lkml.kernel.org/r/6b31721ea92f51ea839e79bd97ade4a75b1eeea2.1512057304.git.luto@kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86/power')
-rw-r--r--arch/x86/power/cpu.c21
1 files changed, 17 insertions, 4 deletions
diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
index 84fcfde53f8f..5191de14f4df 100644
--- a/arch/x86/power/cpu.c
+++ b/arch/x86/power/cpu.c
@@ -226,8 +226,20 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
226 load_idt((const struct desc_ptr *)&ctxt->idt_limit); 226 load_idt((const struct desc_ptr *)&ctxt->idt_limit);
227#endif 227#endif
228 228
229#ifdef CONFIG_X86_64
229 /* 230 /*
230 * segment registers 231 * We need GSBASE restored before percpu access can work.
232 * percpu access can happen in exception handlers or in complicated
233 * helpers like load_gs_index().
234 */
235 wrmsrl(MSR_GS_BASE, ctxt->gs_base);
236#endif
237
238 fix_processor_context();
239
240 /*
241 * Restore segment registers. This happens after restoring the GDT
242 * and LDT, which happen in fix_processor_context().
231 */ 243 */
232#ifdef CONFIG_X86_32 244#ifdef CONFIG_X86_32
233 loadsegment(es, ctxt->es); 245 loadsegment(es, ctxt->es);
@@ -248,13 +260,14 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
248 load_gs_index(ctxt->gs); 260 load_gs_index(ctxt->gs);
249 asm volatile ("movw %0, %%ss" :: "r" (ctxt->ss)); 261 asm volatile ("movw %0, %%ss" :: "r" (ctxt->ss));
250 262
263 /*
264 * Restore FSBASE and user GSBASE after reloading the respective
265 * segment selectors.
266 */
251 wrmsrl(MSR_FS_BASE, ctxt->fs_base); 267 wrmsrl(MSR_FS_BASE, ctxt->fs_base);
252 wrmsrl(MSR_GS_BASE, ctxt->gs_base);
253 wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base); 268 wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
254#endif 269#endif
255 270
256 fix_processor_context();
257
258 do_fpu_end(); 271 do_fpu_end();
259 tsc_verify_tsc_adjust(true); 272 tsc_verify_tsc_adjust(true);
260 x86_platform.restore_sched_clock_state(); 273 x86_platform.restore_sched_clock_state();