• Andy Lutomirski's avatar
    x86/power: Fix some ordering bugs in __restore_processor_context() · 5b06bbcf
    Andy Lutomirski authored
    __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: ca37e57b ("x86/entry/64: Add missing irqflags tracing to native_load_gs_index()")
    Reported-by: default avatarJarkko Nikula <jarkko.nikula@linux.intel.com>
    Signed-off-by: default avatarAndy Lutomirski <luto@kernel.org>
    Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
    Tested-by: default avatarJarkko 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.orgSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
    5b06bbcf
cpu.c 12.3 KB