diff mbox series

powerpc: Interrupt handler stack randomisation

Message ID 20221025033807.1413688-1-rmclure@linux.ibm.com (mailing list archive)
State Changes Requested
Headers show
Series powerpc: Interrupt handler stack randomisation | expand

Checks

Context Check Description
snowpatch_ozlabs/github-powerpc_ppctests success Successfully ran 10 jobs.
snowpatch_ozlabs/github-powerpc_selftests success Successfully ran 10 jobs.
snowpatch_ozlabs/github-powerpc_sparse success Successfully ran 4 jobs.
snowpatch_ozlabs/github-powerpc_clang success Successfully ran 6 jobs.
snowpatch_ozlabs/github-powerpc_kernel_qemu success Successfully ran 23 jobs.

Commit Message

Rohan McLure Oct. 25, 2022, 3:38 a.m. UTC
Stack frames used by syscall handlers support random offsets as of
commit f4a0318f278d (powerpc: add support for syscall stack randomization).
Implement the same for general interrupt handlers, by applying the
random stack offset and then updating this offset from within the
DEFINE_INTERRUPT_HANDLER macros.

Applying this offset perturbs the layout of interrupt handler stack
frames, rendering to the kernel stack more difficult to control by means
of user invoked interrupts.

Link: https://lists.ozlabs.org/pipermail/linuxppc-dev/2022-May/243238.html

Signed-off-by: Rohan McLure <rmclure@linux.ibm.com>
---
 arch/powerpc/include/asm/interrupt.h | 12 ++++++++++++
 1 file changed, 12 insertions(+)

Comments

Christophe Leroy Nov. 3, 2022, 7:52 a.m. UTC | #1
Le 25/10/2022 à 05:38, Rohan McLure a écrit :
> Stack frames used by syscall handlers support random offsets as of
> commit f4a0318f278d (powerpc: add support for syscall stack randomization).
> Implement the same for general interrupt handlers, by applying the
> random stack offset and then updating this offset from within the
> DEFINE_INTERRUPT_HANDLER macros.
> 
> Applying this offset perturbs the layout of interrupt handler stack
> frames, rendering to the kernel stack more difficult to control by means
> of user invoked interrupts.
> 
> Link: https://lists.ozlabs.org/pipermail/linuxppc-dev/2022-May/243238.html
> 
> Signed-off-by: Rohan McLure <rmclure@linux.ibm.com>

Reviewed-by: Christophe Leroy <christophe.leroy@csgroup.eu>


> ---
>   arch/powerpc/include/asm/interrupt.h | 12 ++++++++++++
>   1 file changed, 12 insertions(+)
> 
> diff --git a/arch/powerpc/include/asm/interrupt.h b/arch/powerpc/include/asm/interrupt.h
> index 4745bb9998bd..b7f7beff4e13 100644
> --- a/arch/powerpc/include/asm/interrupt.h
> +++ b/arch/powerpc/include/asm/interrupt.h
> @@ -68,6 +68,7 @@
>   
>   #include <linux/context_tracking.h>
>   #include <linux/hardirq.h>
> +#include <linux/randomize_kstack.h>
>   #include <asm/cputime.h>
>   #include <asm/firmware.h>
>   #include <asm/ftrace.h>
> @@ -448,9 +449,12 @@ interrupt_handler long func(struct pt_regs *regs)			\
>   	long ret;							\
>   									\
>   	__hard_RI_enable();						\
> +	add_random_kstack_offset();					\
>   									\
>   	ret = ____##func (regs);					\
>   									\
> +	choose_random_kstack_offset(mftb());				\
> +									\
>   	return ret;							\
>   }									\
>   NOKPROBE_SYMBOL(func);							\
> @@ -480,9 +484,11 @@ static __always_inline void ____##func(struct pt_regs *regs);		\
>   interrupt_handler void func(struct pt_regs *regs)			\
>   {									\
>   	interrupt_enter_prepare(regs);					\
> +	add_random_kstack_offset();					\
>   									\
>   	____##func (regs);						\
>   									\
> +	choose_random_kstack_offset(mftb());				\
>   	interrupt_exit_prepare(regs);					\
>   }									\
>   NOKPROBE_SYMBOL(func);							\
> @@ -515,9 +521,11 @@ interrupt_handler long func(struct pt_regs *regs)			\
>   	long ret;							\
>   									\
>   	interrupt_enter_prepare(regs);					\
> +	add_random_kstack_offset();					\
>   									\
>   	ret = ____##func (regs);					\
>   									\
> +	choose_random_kstack_offset(mftb());				\
>   	interrupt_exit_prepare(regs);					\
>   									\
>   	return ret;							\
> @@ -548,9 +556,11 @@ static __always_inline void ____##func(struct pt_regs *regs);		\
>   interrupt_handler void func(struct pt_regs *regs)			\
>   {									\
>   	interrupt_async_enter_prepare(regs);				\
> +	add_random_kstack_offset();					\
>   									\
>   	____##func (regs);						\
>   									\
> +	choose_random_kstack_offset(mftb());				\
>   	interrupt_async_exit_prepare(regs);				\
>   }									\
>   NOKPROBE_SYMBOL(func);							\
> @@ -585,9 +595,11 @@ interrupt_handler long func(struct pt_regs *regs)			\
>   	long ret;							\
>   									\
>   	interrupt_nmi_enter_prepare(regs, &state);			\
> +	add_random_kstack_offset();					\
>   									\
>   	ret = ____##func (regs);					\
>   									\
> +	choose_random_kstack_offset(mftb());				\
>   	interrupt_nmi_exit_prepare(regs, &state);			\
>   									\
>   	return ret;							\
Nicholas Piggin Nov. 7, 2022, 11:55 a.m. UTC | #2
On Tue Oct 25, 2022 at 1:38 PM AEST, Rohan McLure wrote:
> Stack frames used by syscall handlers support random offsets as of
> commit f4a0318f278d (powerpc: add support for syscall stack randomization).
> Implement the same for general interrupt handlers, by applying the
> random stack offset and then updating this offset from within the
> DEFINE_INTERRUPT_HANDLER macros.
>
> Applying this offset perturbs the layout of interrupt handler stack
> frames, rendering to the kernel stack more difficult to control by means
> of user invoked interrupts.

Can you randomise the irq/softirq stacks as well with a patch 2?

_Probably_ don't have to do another mftb for those AFAICS. Hard irq
should be driven by one of these handlers (including in the irq replay
case). Softirq fast path is driven from irq_exit() from the async
irq handlers, so that should be pretty well randomized. Softirq
slowpath is done by ksoftirqd using its own stack, so nothing to
be done there.

>
> Link: https://lists.ozlabs.org/pipermail/linuxppc-dev/2022-May/243238.html
>
> Signed-off-by: Rohan McLure <rmclure@linux.ibm.com>
> ---
>  arch/powerpc/include/asm/interrupt.h | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
>
> diff --git a/arch/powerpc/include/asm/interrupt.h b/arch/powerpc/include/asm/interrupt.h
> index 4745bb9998bd..b7f7beff4e13 100644
> --- a/arch/powerpc/include/asm/interrupt.h
> +++ b/arch/powerpc/include/asm/interrupt.h
> @@ -68,6 +68,7 @@
>  
>  #include <linux/context_tracking.h>
>  #include <linux/hardirq.h>
> +#include <linux/randomize_kstack.h>
>  #include <asm/cputime.h>
>  #include <asm/firmware.h>
>  #include <asm/ftrace.h>
> @@ -448,9 +449,12 @@ interrupt_handler long func(struct pt_regs *regs)			\
>  	long ret;							\
>  									\
>  	__hard_RI_enable();						\
> +	add_random_kstack_offset();					\
>  									\
>  	ret = ____##func (regs);					\
>  									\
> +	choose_random_kstack_offset(mftb());				\
> +									\
>  	return ret;							\
>  }									\
>  NOKPROBE_SYMBOL(func);							\
> @@ -480,9 +484,11 @@ static __always_inline void ____##func(struct pt_regs *regs);		\
>  interrupt_handler void func(struct pt_regs *regs)			\
>  {									\
>  	interrupt_enter_prepare(regs);					\
> +	add_random_kstack_offset();					\
>  									\
>  	____##func (regs);						\
>  									\
> +	choose_random_kstack_offset(mftb());				\
>  	interrupt_exit_prepare(regs);					\
>  }									\
>  NOKPROBE_SYMBOL(func);							\

Hmm. It uses per-cpu data, so it actually can't be used for all
interrupt types, HMI and MCE because they're real-mode. SLB because
that might take an SLB fault, and maybe not hash faults either because
they might fault again I think?

You'd have to change the core code to let us put the offset in the paca.
Not sure if 32-bit has any such restrictions (e.g., does 32s need
MSR[RI] enabled before accessing per-cpu data?)

If you can do that that then I'd also put it as the first thing in
the func(), because the enter_prepare code can call non-trivial code
(e.g., irq_enter / nmi_enter).

Thnaks,
Nick
diff mbox series

Patch

diff --git a/arch/powerpc/include/asm/interrupt.h b/arch/powerpc/include/asm/interrupt.h
index 4745bb9998bd..b7f7beff4e13 100644
--- a/arch/powerpc/include/asm/interrupt.h
+++ b/arch/powerpc/include/asm/interrupt.h
@@ -68,6 +68,7 @@ 
 
 #include <linux/context_tracking.h>
 #include <linux/hardirq.h>
+#include <linux/randomize_kstack.h>
 #include <asm/cputime.h>
 #include <asm/firmware.h>
 #include <asm/ftrace.h>
@@ -448,9 +449,12 @@  interrupt_handler long func(struct pt_regs *regs)			\
 	long ret;							\
 									\
 	__hard_RI_enable();						\
+	add_random_kstack_offset();					\
 									\
 	ret = ____##func (regs);					\
 									\
+	choose_random_kstack_offset(mftb());				\
+									\
 	return ret;							\
 }									\
 NOKPROBE_SYMBOL(func);							\
@@ -480,9 +484,11 @@  static __always_inline void ____##func(struct pt_regs *regs);		\
 interrupt_handler void func(struct pt_regs *regs)			\
 {									\
 	interrupt_enter_prepare(regs);					\
+	add_random_kstack_offset();					\
 									\
 	____##func (regs);						\
 									\
+	choose_random_kstack_offset(mftb());				\
 	interrupt_exit_prepare(regs);					\
 }									\
 NOKPROBE_SYMBOL(func);							\
@@ -515,9 +521,11 @@  interrupt_handler long func(struct pt_regs *regs)			\
 	long ret;							\
 									\
 	interrupt_enter_prepare(regs);					\
+	add_random_kstack_offset();					\
 									\
 	ret = ____##func (regs);					\
 									\
+	choose_random_kstack_offset(mftb());				\
 	interrupt_exit_prepare(regs);					\
 									\
 	return ret;							\
@@ -548,9 +556,11 @@  static __always_inline void ____##func(struct pt_regs *regs);		\
 interrupt_handler void func(struct pt_regs *regs)			\
 {									\
 	interrupt_async_enter_prepare(regs);				\
+	add_random_kstack_offset();					\
 									\
 	____##func (regs);						\
 									\
+	choose_random_kstack_offset(mftb());				\
 	interrupt_async_exit_prepare(regs);				\
 }									\
 NOKPROBE_SYMBOL(func);							\
@@ -585,9 +595,11 @@  interrupt_handler long func(struct pt_regs *regs)			\
 	long ret;							\
 									\
 	interrupt_nmi_enter_prepare(regs, &state);			\
+	add_random_kstack_offset();					\
 									\
 	ret = ____##func (regs);					\
 									\
+	choose_random_kstack_offset(mftb());				\
 	interrupt_nmi_exit_prepare(regs, &state);			\
 									\
 	return ret;							\