1 From ebd5404a5e0055b9fee2e43589417dada01ac26f Mon Sep 17 00:00:00 2001
2 From: Andy Lutomirski <luto@kernel.org>
3 Date: Thu, 30 Nov 2017 07:57:57 -0800
4 Subject: x86/power: Fix some ordering bugs in __restore_processor_context()
6 [ Upstream commit 5b06bbcfc2c621da3009da8decb7511500c293ed ]
8 __restore_processor_context() had a couple of ordering bugs. It
9 restored GSBASE after calling load_gs_index(), and the latter can
10 call into tracing code. It also tried to restore segment registers
11 before restoring the LDT, which is straight-up wrong.
13 Reorder the code so that we restore GSBASE, then the descriptor
14 tables, then the segments.
16 This fixes two bugs. First, it fixes a regression that broke resume
17 under certain configurations due to irqflag tracing in
18 native_load_gs_index(). Second, it fixes resume when the userspace
19 process that initiated suspect had funny segments. The latter can be
20 reproduced by compiling this:
22 // SPDX-License-Identifier: GPL-2.0
24 * ldt_echo.c - Echo argv[1] while using an LDT segment
27 int main(int argc, char **argv)
33 const struct user_desc desc = {
38 .contents = 0, /* Data, grow-up */
46 errx(1, "Usage: %s STRING", argv[0]);
48 len = asprintf(&buf, "%s\n", argv[1]);
50 errx(1, "Out of memory");
52 ret = syscall(SYS_modify_ldt, 1, &desc, sizeof(desc));
58 asm volatile ("movw %0, %%es" :: "rm" ((unsigned short)7));
63 and running ldt_echo >/sys/power/mem
65 Without the fix, the latter causes a triple fault on resume.
67 Fixes: ca37e57bbe0c ("x86/entry/64: Add missing irqflags tracing to native_load_gs_index()")
68 Reported-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
69 Signed-off-by: Andy Lutomirski <luto@kernel.org>
70 Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
71 Tested-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
72 Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
73 Cc: Borislav Petkov <bp@alien8.de>
74 Cc: Linus Torvalds <torvalds@linux-foundation.org>
75 Link: https://lkml.kernel.org/r/6b31721ea92f51ea839e79bd97ade4a75b1eeea2.1512057304.git.luto@kernel.org
76 Signed-off-by: Ingo Molnar <mingo@kernel.org>
77 Signed-off-by: Sasha Levin <sashal@kernel.org>
79 arch/x86/power/cpu.c | 21 +++++++++++++++++----
80 1 file changed, 17 insertions(+), 4 deletions(-)
82 diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
83 index 53cace2ec0e2..73063dfed476 100644
84 --- a/arch/x86/power/cpu.c
85 +++ b/arch/x86/power/cpu.c
86 @@ -222,8 +222,20 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
87 load_idt((const struct desc_ptr *)&ctxt->idt_limit);
93 + * We need GSBASE restored before percpu access can work.
94 + * percpu access can happen in exception handlers or in complicated
95 + * helpers like load_gs_index().
97 + wrmsrl(MSR_GS_BASE, ctxt->gs_base);
100 + fix_processor_context();
103 + * Restore segment registers. This happens after restoring the GDT
104 + * and LDT, which happen in fix_processor_context().
107 loadsegment(es, ctxt->es);
108 @@ -244,13 +256,14 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
109 load_gs_index(ctxt->gs);
110 asm volatile ("movw %0, %%ss" :: "r" (ctxt->ss));
113 + * Restore FSBASE and user GSBASE after reloading the respective
114 + * segment selectors.
116 wrmsrl(MSR_FS_BASE, ctxt->fs_base);
117 - wrmsrl(MSR_GS_BASE, ctxt->gs_base);
118 wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
121 - fix_processor_context();
124 x86_platform.restore_sched_clock_state();