aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@kernel.org>2016-09-12 18:05:51 -0400
committerIngo Molnar <mingo@kernel.org>2016-09-13 14:34:16 -0400
commit85063fac1f72419eec4349621fe829b07f9acb1e (patch)
treea8cfff2b57faf887bb18c7c54c3814234688e1e4
parent1ef0199a1a698d82ecd39d11d1daa3f4ab006c75 (diff)
x86/entry/64: Clean up and document espfix64 stack setup
The espfix64 setup code was a bit inscrutible and contained an unnecessary push of RAX. Remove that push, update all the stack offsets to match, and document the whole mess. Reported-By: Borislav Petkov <bp@alien8.de> Signed-off-by: Andy Lutomirski <luto@kernel.org> Reviewed-by: Borislav Petkov <bp@suse.de> Cc: Borislav Petkov <bp@alien8.de> Cc: Brian Gerst <brgerst@gmail.com> Cc: Denys Vlasenko <dvlasenk@redhat.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/e5459eb10cf1175c8b36b840bc425f210d045f35.1473717910.git.luto@kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/entry/entry_64.S64
1 files changed, 53 insertions, 11 deletions
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
index c0373d667674..e7fba58f4d9c 100644
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -586,27 +586,69 @@ native_irq_return_iret:
586 586
587#ifdef CONFIG_X86_ESPFIX64 587#ifdef CONFIG_X86_ESPFIX64
588native_irq_return_ldt: 588native_irq_return_ldt:
589 pushq %rax 589 /*
590 pushq %rdi 590 * We are running with user GSBASE. All GPRs contain their user
591 * values. We have a percpu ESPFIX stack that is eight slots
592 * long (see ESPFIX_STACK_SIZE). espfix_waddr points to the bottom
593 * of the ESPFIX stack.
594 *
595 * We clobber RAX and RDI in this code. We stash RDI on the
596 * normal stack and RAX on the ESPFIX stack.
597 *
598 * The ESPFIX stack layout we set up looks like this:
599 *
600 * --- top of ESPFIX stack ---
601 * SS
602 * RSP
603 * RFLAGS
604 * CS
605 * RIP <-- RSP points here when we're done
606 * RAX <-- espfix_waddr points here
607 * --- bottom of ESPFIX stack ---
608 */
609
610 pushq %rdi /* Stash user RDI */
591 SWAPGS 611 SWAPGS
592 movq PER_CPU_VAR(espfix_waddr), %rdi 612 movq PER_CPU_VAR(espfix_waddr), %rdi
593 movq %rax, (0*8)(%rdi) /* RAX */ 613 movq %rax, (0*8)(%rdi) /* user RAX */
594 movq (2*8)(%rsp), %rax /* RIP */ 614 movq (1*8)(%rsp), %rax /* user RIP */
595 movq %rax, (1*8)(%rdi) 615 movq %rax, (1*8)(%rdi)
596 movq (3*8)(%rsp), %rax /* CS */ 616 movq (2*8)(%rsp), %rax /* user CS */
597 movq %rax, (2*8)(%rdi) 617 movq %rax, (2*8)(%rdi)
598 movq (4*8)(%rsp), %rax /* RFLAGS */ 618 movq (3*8)(%rsp), %rax /* user RFLAGS */
599 movq %rax, (3*8)(%rdi) 619 movq %rax, (3*8)(%rdi)
600 movq (6*8)(%rsp), %rax /* SS */ 620 movq (5*8)(%rsp), %rax /* user SS */
601 movq %rax, (5*8)(%rdi) 621 movq %rax, (5*8)(%rdi)
602 movq (5*8)(%rsp), %rax /* RSP */ 622 movq (4*8)(%rsp), %rax /* user RSP */
603 movq %rax, (4*8)(%rdi) 623 movq %rax, (4*8)(%rdi)
604 andl $0xffff0000, %eax 624 /* Now RAX == RSP. */
605 popq %rdi 625
626 andl $0xffff0000, %eax /* RAX = (RSP & 0xffff0000) */
627 popq %rdi /* Restore user RDI */
628
629 /*
630 * espfix_stack[31:16] == 0. The page tables are set up such that
631 * (espfix_stack | (X & 0xffff0000)) points to a read-only alias of
632 * espfix_waddr for any X. That is, there are 65536 RO aliases of
633 * the same page. Set up RSP so that RSP[31:16] contains the
634 * respective 16 bits of the /userspace/ RSP and RSP nonetheless
635 * still points to an RO alias of the ESPFIX stack.
636 */
606 orq PER_CPU_VAR(espfix_stack), %rax 637 orq PER_CPU_VAR(espfix_stack), %rax
607 SWAPGS 638 SWAPGS
608 movq %rax, %rsp 639 movq %rax, %rsp
609 popq %rax 640
641 /*
642 * At this point, we cannot write to the stack any more, but we can
643 * still read.
644 */
645 popq %rax /* Restore user RAX */
646
647 /*
648 * RSP now points to an ordinary IRET frame, except that the page
649 * is read-only and RSP[31:16] are preloaded with the userspace
650 * values. We can now IRET back to userspace.
651 */
610 jmp native_irq_return_iret 652 jmp native_irq_return_iret
611#endif 653#endif
612END(common_interrupt) 654END(common_interrupt)