| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- From 2a767692d6140051e569ab59a1440b3760839e03 Mon Sep 17 00:00:00 2001
- From: Andy Lutomirski <[email protected]>
- Date: Tue, 11 Jul 2017 10:33:38 -0500
- Subject: [PATCH 018/241] x86/entry/64: Refactor IRQ stacks and make them
- NMI-safe
- MIME-Version: 1.0
- Content-Type: text/plain; charset=UTF-8
- Content-Transfer-Encoding: 8bit
- CVE-2017-5754
- This will allow IRQ stacks to nest inside NMIs or similar entries
- that can happen during IRQ stack setup or teardown.
- The new macros won't work correctly if they're invoked with IRQs on.
- Add a check under CONFIG_DEBUG_ENTRY to detect that.
- Signed-off-by: Andy Lutomirski <[email protected]>
- [ Use %r10 instead of %r11 in xen_do_hypervisor_callback to make objtool
- and ORC unwinder's lives a little easier. ]
- Signed-off-by: Josh Poimboeuf <[email protected]>
- Cc: Borislav Petkov <[email protected]>
- Cc: Brian Gerst <[email protected]>
- Cc: Denys Vlasenko <[email protected]>
- Cc: H. Peter Anvin <[email protected]>
- Cc: Jiri Slaby <[email protected]>
- Cc: Linus Torvalds <[email protected]>
- Cc: Mike Galbraith <[email protected]>
- Cc: Peter Zijlstra <[email protected]>
- Cc: Thomas Gleixner <[email protected]>
- Cc: [email protected]
- Link: http://lkml.kernel.org/r/b0b2ff5fb97d2da2e1d7e1f380190c92545c8bb5.1499786555.git.jpoimboe@redhat.com
- Signed-off-by: Ingo Molnar <[email protected]>
- (cherry picked from commit 1d3e53e8624a3ec85f4041ca6d973da7c1575938)
- Signed-off-by: Andy Whitcroft <[email protected]>
- Signed-off-by: Kleber Sacilotto de Souza <[email protected]>
- (cherry picked from commit be58b042e135d0ee777a54798f33015857d7e2e0)
- Signed-off-by: Fabian Grünbichler <[email protected]>
- ---
- arch/x86/kernel/process_64.c | 3 ++
- arch/x86/Kconfig.debug | 2 --
- arch/x86/entry/entry_64.S | 85 +++++++++++++++++++++++++++++++-------------
- 3 files changed, 64 insertions(+), 26 deletions(-)
- diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
- index fe56e6f93cbb..1e7701c4cd80 100644
- --- a/arch/x86/kernel/process_64.c
- +++ b/arch/x86/kernel/process_64.c
- @@ -404,6 +404,9 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
- int cpu = smp_processor_id();
- struct tss_struct *tss = &per_cpu(cpu_tss, cpu);
-
- + WARN_ON_ONCE(IS_ENABLED(CONFIG_DEBUG_ENTRY) &&
- + this_cpu_read(irq_count) != -1);
- +
- switch_fpu_prepare(prev_fpu, cpu);
-
- /* We must save %fs and %gs before load_TLS() because
- diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
- index cd20ca0b4043..1fc519f3c49e 100644
- --- a/arch/x86/Kconfig.debug
- +++ b/arch/x86/Kconfig.debug
- @@ -305,8 +305,6 @@ config DEBUG_ENTRY
- Some of these sanity checks may slow down kernel entries and
- exits or otherwise impact performance.
-
- - This is currently used to help test NMI code.
- -
- If unsure, say N.
-
- config DEBUG_NMI_SELFTEST
- diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
- index 6d078b89a5e8..07b4056af8a8 100644
- --- a/arch/x86/entry/entry_64.S
- +++ b/arch/x86/entry/entry_64.S
- @@ -447,6 +447,59 @@ ENTRY(irq_entries_start)
- .endr
- END(irq_entries_start)
-
- +.macro DEBUG_ENTRY_ASSERT_IRQS_OFF
- +#ifdef CONFIG_DEBUG_ENTRY
- + pushfq
- + testl $X86_EFLAGS_IF, (%rsp)
- + jz .Lokay_\@
- + ud2
- +.Lokay_\@:
- + addq $8, %rsp
- +#endif
- +.endm
- +
- +/*
- + * Enters the IRQ stack if we're not already using it. NMI-safe. Clobbers
- + * flags and puts old RSP into old_rsp, and leaves all other GPRs alone.
- + * Requires kernel GSBASE.
- + *
- + * The invariant is that, if irq_count != -1, then the IRQ stack is in use.
- + */
- +.macro ENTER_IRQ_STACK old_rsp
- + DEBUG_ENTRY_ASSERT_IRQS_OFF
- + movq %rsp, \old_rsp
- + incl PER_CPU_VAR(irq_count)
- +
- + /*
- + * Right now, if we just incremented irq_count to zero, we've
- + * claimed the IRQ stack but we haven't switched to it yet.
- + *
- + * If anything is added that can interrupt us here without using IST,
- + * it must be *extremely* careful to limit its stack usage. This
- + * could include kprobes and a hypothetical future IST-less #DB
- + * handler.
- + */
- +
- + cmovzq PER_CPU_VAR(irq_stack_ptr), %rsp
- + pushq \old_rsp
- +.endm
- +
- +/*
- + * Undoes ENTER_IRQ_STACK.
- + */
- +.macro LEAVE_IRQ_STACK
- + DEBUG_ENTRY_ASSERT_IRQS_OFF
- + /* We need to be off the IRQ stack before decrementing irq_count. */
- + popq %rsp
- +
- + /*
- + * As in ENTER_IRQ_STACK, irq_count == 0, we are still claiming
- + * the irq stack but we're not on it.
- + */
- +
- + decl PER_CPU_VAR(irq_count)
- +.endm
- +
- /*
- * Interrupt entry/exit.
- *
- @@ -485,17 +538,7 @@ END(irq_entries_start)
- CALL_enter_from_user_mode
-
- 1:
- - /*
- - * Save previous stack pointer, optionally switch to interrupt stack.
- - * irq_count is used to check if a CPU is already on an interrupt stack
- - * or not. While this is essentially redundant with preempt_count it is
- - * a little cheaper to use a separate counter in the PDA (short of
- - * moving irq_enter into assembly, which would be too much work)
- - */
- - movq %rsp, %rdi
- - incl PER_CPU_VAR(irq_count)
- - cmovzq PER_CPU_VAR(irq_stack_ptr), %rsp
- - pushq %rdi
- + ENTER_IRQ_STACK old_rsp=%rdi
- /* We entered an interrupt context - irqs are off: */
- TRACE_IRQS_OFF
-
- @@ -515,10 +558,8 @@ common_interrupt:
- ret_from_intr:
- DISABLE_INTERRUPTS(CLBR_ANY)
- TRACE_IRQS_OFF
- - decl PER_CPU_VAR(irq_count)
-
- - /* Restore saved previous stack */
- - popq %rsp
- + LEAVE_IRQ_STACK
-
- testb $3, CS(%rsp)
- jz retint_kernel
- @@ -892,12 +933,10 @@ bad_gs:
- ENTRY(do_softirq_own_stack)
- pushq %rbp
- mov %rsp, %rbp
- - incl PER_CPU_VAR(irq_count)
- - cmove PER_CPU_VAR(irq_stack_ptr), %rsp
- - push %rbp /* frame pointer backlink */
- + ENTER_IRQ_STACK old_rsp=%r11
- call __do_softirq
- + LEAVE_IRQ_STACK
- leaveq
- - decl PER_CPU_VAR(irq_count)
- ret
- END(do_softirq_own_stack)
-
- @@ -924,13 +963,11 @@ ENTRY(xen_do_hypervisor_callback) /* do_hypervisor_callback(struct *pt_regs) */
- * see the correct pointer to the pt_regs
- */
- movq %rdi, %rsp /* we don't return, adjust the stack frame */
- -11: incl PER_CPU_VAR(irq_count)
- - movq %rsp, %rbp
- - cmovzq PER_CPU_VAR(irq_stack_ptr), %rsp
- - pushq %rbp /* frame pointer backlink */
- +
- + ENTER_IRQ_STACK old_rsp=%r10
- call xen_evtchn_do_upcall
- - popq %rsp
- - decl PER_CPU_VAR(irq_count)
- + LEAVE_IRQ_STACK
- +
- #ifndef CONFIG_PREEMPT
- call xen_maybe_preempt_hcall
- #endif
- --
- 2.14.2
|