[tip:x86/urgent] x86/power: Fix some ordering bugs in __restore_processor_context()

tip-bot for Andy Lutomirski
2017-12-04T22:50:24Z

Commit-ID: cdf577209aad4cdbe3455d3efa6cf631f838c55d
Gitweb: https://git.kernel.org/tip/cdf577209aad4cdbe3455d3efa6cf631f838c55d
Author: Andy Lutomirski <luto@kernel.org>
AuthorDate: Thu, 30 Nov 2017 07:57:57 -0800
Committer: Thomas Gleixner <tglx@linutronix.de>
CommitDate: Mon, 4 Dec 2017 23:41:42 +0100

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

---
arch/x86/power/cpu.c | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
index 84fcfde..5191de1 100644