linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Thomas Gleixner <tglx@linutronix.de>
To: LKML <linux-kernel@vger.kernel.org>
Cc: x86@kernel.org, Josh Poimboeuf <jpoimboe@redhat.com>,
	Kees Cook <keescook@chromium.org>
Subject: [patch 05/12] x86/irq: Provide macro for inlining irq stack switching
Date: Thu, 04 Feb 2021 21:49:08 +0100	[thread overview]
Message-ID: <20210204211154.618389756@linutronix.de> (raw)
In-Reply-To: 20210204204903.350275743@linutronix.de

The effort to make the ASM entry code slim and unified moved the irq stack
switching out of the low level ASM code so that the whole return from
interrupt work and state handling can be done in C and the ASM code just
handles the low level details of entry and exit.

This ended up being a suboptimal implementation for various reasons
(including tooling). The main pain points are:

 - The indirect call which is expensive thanks to retpoline

 - The inability to stay on the irq stack for softirq processing on return
   from interrupt

 - The fact that the stack switching code ends up being an easy to target
   exploit gadget.

Prepare for inlining the stack switching logic into the C entry points by
providing a ASM macro which contains the guts of the switching mechanism:

  1) Store RSP at the top of the irq stack
  2) Switch RSP to the irq stack
  3) Invoke code
  4) Pop the original RSP back

Document the unholy asm() logic while at it to reduce the amount of head
scratching required a half year from now.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 arch/x86/include/asm/irq_stack.h |  104 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 104 insertions(+)

--- a/arch/x86/include/asm/irq_stack.h
+++ b/arch/x86/include/asm/irq_stack.h
@@ -7,6 +7,110 @@
 #include <asm/processor.h>
 
 #ifdef CONFIG_X86_64
+
+#ifdef CONFIG_UNWINDER_FRAME_POINTER
+# define IRQSTACK_CALL_CONSTRAINT	, ASM_CALL_CONSTRAINT
+#else
+# define IRQSTACK_CALL_CONSTRAINT
+#endif
+
+/*
+ * Macro to inline switching to an interrupt stack and invoking function
+ * calls from there. The following rules apply:
+ *
+ * - Ordering:
+ *
+ *   1. Write the stack pointer content into the top most place of
+ *	the irq stack. This ensures that the various unwinders can
+ *	link back to the original stack.
+ *
+ *   2. Switch the stack pointer to the top of the irq stack.
+ *
+ *   3. Invoke whatever needs to be done (@asm_call argument)
+ *
+ *   4. Pop the original stack pointer from the top of the irq stack
+ *	which brings it back to the original stack where it left off.
+ *
+ * - Function invocation:
+ *
+ *   To allow flexible usage of the macro, the actual function code including
+ *   the store of the arguments in the call ABI registers is handed in via
+ *   the @asm_call argument.
+ *
+ * - Local variables:
+ *
+ *   @tos:
+ *	The @tos variable holds a pointer to the top of the irq stack and
+ *	_must_ be allocated in a non-callee saved register as this is a
+ *	restriction coming from objtool.
+ *
+ *	Note, that (tos) is both in input and output constraints to ensure
+ *	that the compiler does not assume that R11 is left untouched in
+ *	case this macro is used in some place where the per cpu interrupt
+ *	stack pointer is used again afterwards
+ *
+ * - Function arguments:
+ *        The function argument(s) if any have to be defined in register
+ *	  variables at the place where this is invoked. Storing the
+ *	  argument(s) in the proper register(s) is part of the @asm_call
+ *
+ * - Constraints:
+ *
+ *   The constraints have to be done very carefully because the compiler
+ *   does not know about the assembly call.
+ *
+ *   output:
+ *     As documented already above the @tos variable is required to be in
+ *     the output constraints to make the compiler aware that R11 cannot be
+ *     reused after the asm() statement.
+ *
+ *     For builds with CONFIG_UNWIND_FRAME_POINTER ASM_CALL_CONSTRAINT is
+ *     required as well as this prevents certain creative GCC variants from
+ *     misplacing the ASM code.
+ *
+ *  input:
+ *    - func:
+ *	  Immediate, which tells the compiler that the function is referenced.
+ *
+ *    - tos:
+ *	  Register. The actual register is defined by the variable declaration.
+ *
+ *    - function arguments:
+ *	  The constraints are handed in via the 'argconstr' argument list. They
+ *	  describe the register arguments which are used in @asm_call.
+ *
+ *  clobbers:
+ *     Function calls can clobber anything except the callee-saved
+ *     registers. Tell the compiler.
+ */
+#define __call_on_irqstack(func, asm_call, constr...)			\
+{									\
+	register void *tos asm("r11");					\
+									\
+	tos = ((void *)__this_cpu_read(hardirq_stack_ptr));		\
+									\
+	asm_inline volatile(						\
+	"movq	%%rsp, (%[__tos])			\n"		\
+	"movq	%[__tos], %%rsp				\n"		\
+									\
+	asm_call							\
+									\
+	"popq	%%rsp					\n"		\
+									\
+	: "+r" (tos) IRQSTACK_CALL_CONSTRAINT				\
+	: [__func] "i" (func), [__tos] "r" (tos) constr			\
+	: "cc", "rax", "rcx", "rdx", "rsi", "rdi", "r8", "r9", "r10",	\
+	  "memory"							\
+	);								\
+}
+
+/* Macros to assert type correctness for run_*_on_irqstack macros */
+#define assert_function_type(func, proto)				\
+	static_assert(__builtin_types_compatible_p(typeof(&func), proto))
+
+#define assert_arg_type(arg, proto)					\
+	static_assert(__builtin_types_compatible_p(typeof(arg), proto))
+
 static __always_inline bool irqstack_active(void)
 {
 	return __this_cpu_read(hardirq_stack_inuse);


  parent reply	other threads:[~2021-02-05  0:59 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-02-04 20:49 [patch 00/12] x86/irq/64: Inline irq stack switching Thomas Gleixner
2021-02-04 20:49 ` [patch 01/12] x86/entry: Fix instrumentation annotation Thomas Gleixner
2021-02-05 12:02   ` Borislav Petkov
2021-02-04 20:49 ` [patch 02/12] x86/irq: Sanitize irq stack tracking Thomas Gleixner
2021-02-04 20:49 ` [patch 03/12] x86/irq/64: Adjust the per CPU irq stack pointer by 8 Thomas Gleixner
2021-02-05 13:53   ` Peter Zijlstra
2021-02-05 15:00     ` Thomas Gleixner
2021-02-04 20:49 ` [patch 04/12] x86/apic: Split out spurious handling code Thomas Gleixner
2021-02-04 20:49 ` Thomas Gleixner [this message]
2021-02-08 15:06   ` [patch 05/12] x86/irq: Provide macro for inlining irq stack switching Borislav Petkov
2021-02-08 20:42   ` Josh Poimboeuf
2021-02-09 15:12     ` Thomas Gleixner
2021-02-09 16:22       ` Josh Poimboeuf
2021-02-09 18:14         ` Thomas Gleixner
2021-02-04 20:49 ` [patch 06/12] x86/entry: Convert system vectors to irq stack macro Thomas Gleixner
2021-02-05  3:52   ` kernel test robot
2021-02-05 14:13     ` Peter Zijlstra
2021-02-07  8:15       ` [kbuild-all] " Rong Chen
2021-02-08 14:19         ` Borislav Petkov
2021-02-09  8:57           ` Rong Chen
2021-02-09 10:46             ` Borislav Petkov
2021-02-04 20:49 ` [patch 07/12] x86/entry: Convert device interrupts to inline stack switching Thomas Gleixner
2021-02-04 20:49 ` [patch 08/12] x86/entry: Use run_sysvec_on_irqstack_cond() for XEN upcall Thomas Gleixner
2021-02-05  7:28   ` kernel test robot
2021-02-04 20:49 ` [patch 09/12] x86/softirq: Remove indirection in do_softirq_own_stack() Thomas Gleixner
2021-02-04 20:49 ` [patch 10/12] x86: Select CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK Thomas Gleixner
2021-02-04 20:49 ` [patch 11/12] softirq: Allow inlining do_softirq_own_stack() Thomas Gleixner
2021-02-05 10:14   ` Lai Jiangshan
2021-02-05 11:38     ` Thomas Gleixner
2021-02-09 20:43       ` Thomas Gleixner
2021-02-04 20:49 ` [patch 12/12] x86/softirq/64: Inline do_softirq_own_stack() Thomas Gleixner
2021-02-08 21:47 ` [patch 00/12] x86/irq/64: Inline irq stack switching Kees Cook
2021-02-05 11:03 [patch 05/12] x86/irq: Provide macro for inlining " Uros Bizjak
2021-02-05 13:24 ` Thomas Gleixner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210204211154.618389756@linutronix.de \
    --to=tglx@linutronix.de \
    --cc=jpoimboe@redhat.com \
    --cc=keescook@chromium.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).