Hi,
This is the new version of stackleak for arm64 to go with v14 of the
series for x86. I have a cover letter and few more cc's to go along with
some of the prep work.
I also apologize for terrible versioning on these series. Usually I try
to just reply to the top level patch with this addition and not actually
put a version on it. I negelcted to do that last time but as mentioned
this is inteded to go with v14.
Laura Abbott (2):
arm64: Introduce current_stack_type
arm64: Clear the stack
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/processor.h | 17 +++++
arch/arm64/include/asm/sdei.h | 8 ++-
arch/arm64/include/asm/stacktrace.h | 94 ++++++++++++++++++++++-----
arch/arm64/kernel/entry.S | 7 ++
arch/arm64/kernel/process.c | 32 +++++++++
arch/arm64/kernel/ptrace.c | 2 +-
arch/arm64/kernel/sdei.c | 21 +++++-
arch/arm64/kvm/hyp/Makefile | 3 +-
drivers/firmware/efi/libstub/Makefile | 3 +-
include/linux/stackleak.h | 1 +
11 files changed, 165 insertions(+), 24 deletions(-)
--
2.17.1
Implementation of stackleak based heavily on the x86 version
Signed-off-by: Laura Abbott <[email protected]>
---
Since last time: Minor style cleanups. Re-wrote check_alloca to
correctly handle all stack types. While doing that, I also realized
current_top_of_stack was incorrect so I fixed that as well.
---
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/processor.h | 17 ++++++++++++++
arch/arm64/kernel/entry.S | 7 ++++++
arch/arm64/kernel/process.c | 32 +++++++++++++++++++++++++++
arch/arm64/kvm/hyp/Makefile | 3 ++-
drivers/firmware/efi/libstub/Makefile | 3 ++-
include/linux/stackleak.h | 1 +
7 files changed, 62 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 42c090cf0292..216d36a49ab5 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -96,6 +96,7 @@ config ARM64
select HAVE_ARCH_MMAP_RND_BITS
select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPAT
select HAVE_ARCH_SECCOMP_FILTER
+ select HAVE_ARCH_STACKLEAK
select HAVE_ARCH_THREAD_STRUCT_WHITELIST
select HAVE_ARCH_TRACEHOOK
select HAVE_ARCH_TRANSPARENT_HUGEPAGE
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index a73ae1e49200..4f3062ee22c6 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -266,5 +266,22 @@ extern void __init minsigstksz_setup(void);
#define SVE_SET_VL(arg) sve_set_current_vl(arg)
#define SVE_GET_VL() sve_get_current_vl()
+/*
+ * For CONFIG_STACKLEAK
+ *
+ * These need to be macros because otherwise we get stuck in a nightmare
+ * of header definitions for the use of task_stack_page.
+ */
+
+#define current_top_of_stack() \
+({ \
+ unsigned long _low = 0; \
+ unsigned long _high = 0; \
+ \
+ current_stack_type(current, current_stack_pointer, &_low, &_high); \
+ _high; \
+})
+#define on_thread_stack() (on_task_stack(current, current_stack_pointer, NULL, NULL))
+
#endif /* __ASSEMBLY__ */
#endif /* __ASM_PROCESSOR_H */
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 28ad8799406f..67d12016063d 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -431,6 +431,11 @@ tsk .req x28 // current thread_info
.text
+ .macro stackleak_erase
+#ifdef CONFIG_GCC_PLUGIN_STACKLEAK
+ bl stackleak_erase
+#endif
+ .endm
/*
* Exception vectors.
*/
@@ -910,6 +915,7 @@ ret_fast_syscall:
and x2, x1, #_TIF_WORK_MASK
cbnz x2, work_pending
enable_step_tsk x1, x2
+ stackleak_erase
kernel_exit 0
ret_fast_syscall_trace:
enable_daif
@@ -936,6 +942,7 @@ ret_to_user:
cbnz x2, work_pending
finish_ret_to_user:
enable_step_tsk x1, x2
+ stackleak_erase
kernel_exit 0
ENDPROC(ret_to_user)
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index e10bc363f533..904defa36689 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -493,3 +493,35 @@ void arch_setup_new_exec(void)
{
current->mm->context.flags = is_compat_task() ? MMCF_AARCH32 : 0;
}
+
+#ifdef CONFIG_GCC_PLUGIN_STACKLEAK
+void __used stackleak_check_alloca(unsigned long size)
+{
+ unsigned long stack_left;
+ enum stack_type type;
+ unsigned long current_sp = current_stack_pointer;
+ unsigned long low, high;
+
+ type = current_stack_type(current, current_sp, &low, &high);
+ BUG_ON(type == STACK_TYPE_UNKNOWN);
+
+ stack_left = current_sp - low;
+
+ if (size >= stack_left) {
+ /*
+ * Kernel stack depth overflow is detected, let's report that.
+ * If CONFIG_VMAP_STACK is enabled, we can safely use BUG().
+ * If CONFIG_VMAP_STACK is disabled, BUG() handling can corrupt
+ * the neighbour memory. CONFIG_SCHED_STACK_END_CHECK calls
+ * panic() in a similar situation, so let's do the same if that
+ * option is on. Otherwise just use BUG() and hope for the best.
+ */
+#if !defined(CONFIG_VMAP_STACK) && defined(CONFIG_SCHED_STACK_END_CHECK)
+ panic("alloca() over the kernel stack boundary\n");
+#else
+ BUG();
+#endif
+ }
+}
+EXPORT_SYMBOL(stackleak_check_alloca);
+#endif
diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
index 4313f7475333..2fabc2dc1966 100644
--- a/arch/arm64/kvm/hyp/Makefile
+++ b/arch/arm64/kvm/hyp/Makefile
@@ -3,7 +3,8 @@
# Makefile for Kernel-based Virtual Machine module, HYP part
#
-ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING
+ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING \
+ $(DISABLE_STACKLEAK_PLUGIN)
KVM=../../../../virt/kvm
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index a34e9290a699..25dd2a14560d 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -20,7 +20,8 @@ cflags-$(CONFIG_EFI_ARMSTUB) += -I$(srctree)/scripts/dtc/libfdt
KBUILD_CFLAGS := $(cflags-y) -DDISABLE_BRANCH_PROFILING \
-D__NO_FORTIFY \
$(call cc-option,-ffreestanding) \
- $(call cc-option,-fno-stack-protector)
+ $(call cc-option,-fno-stack-protector) \
+ $(DISABLE_STACKLEAK_PLUGIN)
GCOV_PROFILE := n
KASAN_SANITIZE := n
diff --git a/include/linux/stackleak.h b/include/linux/stackleak.h
index b911b973d328..08420ec6b7c3 100644
--- a/include/linux/stackleak.h
+++ b/include/linux/stackleak.h
@@ -5,6 +5,7 @@
#include <linux/sched.h>
#include <linux/sched/task_stack.h>
+#include <asm/stacktrace.h>
/*
* Check that the poison value points to the unused hole in the
* virtual memory map for your platform.
--
2.17.1
In preparation for enabling the stackleak plugin on arm64,
we need a way to get the bounds of the current stack.
Introduce a new primitive current_stack_type which is similar
to x86's get_stack_info. Utilize that to rework
on_accessible_stack slightly as well.
Signed-off-by: Laura Abbott <[email protected]>
---
So this did end up looking quite a bit like get_stack_info but I didn't
really see the need to integrate this more than this. I do think
actually enumerating the types makes things a bit cleaner.
---
arch/arm64/include/asm/sdei.h | 8 ++-
arch/arm64/include/asm/stacktrace.h | 94 ++++++++++++++++++++++++-----
arch/arm64/kernel/ptrace.c | 2 +-
arch/arm64/kernel/sdei.c | 21 ++++++-
4 files changed, 103 insertions(+), 22 deletions(-)
diff --git a/arch/arm64/include/asm/sdei.h b/arch/arm64/include/asm/sdei.h
index e073e6886685..34f7b203845b 100644
--- a/arch/arm64/include/asm/sdei.h
+++ b/arch/arm64/include/asm/sdei.h
@@ -40,15 +40,17 @@ asmlinkage unsigned long __sdei_handler(struct pt_regs *regs,
unsigned long sdei_arch_get_entry_point(int conduit);
#define sdei_arch_get_entry_point(x) sdei_arch_get_entry_point(x)
-bool _on_sdei_stack(unsigned long sp);
-static inline bool on_sdei_stack(unsigned long sp)
+bool _on_sdei_stack(unsigned long sp, unsigned long *, unsigned long *);
+static inline bool on_sdei_stack(unsigned long sp,
+ unsigned long *stack_low,
+ unsigned long *stack_high)
{
if (!IS_ENABLED(CONFIG_VMAP_STACK))
return false;
if (!IS_ENABLED(CONFIG_ARM_SDE_INTERFACE))
return false;
if (in_nmi())
- return _on_sdei_stack(sp);
+ return _on_sdei_stack(sp, stack_low, stack_high);
return false;
}
diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h
index 902f9edacbea..9855a0425e64 100644
--- a/arch/arm64/include/asm/stacktrace.h
+++ b/arch/arm64/include/asm/stacktrace.h
@@ -39,7 +39,9 @@ extern void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk);
DECLARE_PER_CPU(unsigned long *, irq_stack_ptr);
-static inline bool on_irq_stack(unsigned long sp)
+static inline bool on_irq_stack(unsigned long sp,
+ unsigned long *stack_low,
+ unsigned long *stack_high)
{
unsigned long low = (unsigned long)raw_cpu_read(irq_stack_ptr);
unsigned long high = low + IRQ_STACK_SIZE;
@@ -47,47 +49,109 @@ static inline bool on_irq_stack(unsigned long sp)
if (!low)
return false;
- return (low <= sp && sp < high);
+ if (sp < low || sp >= high)
+ return false;
+
+ if (stack_low && stack_high) {
+ *stack_low = low;
+ *stack_high = high;
+ }
+
+ return true;
}
-static inline bool on_task_stack(struct task_struct *tsk, unsigned long sp)
+static inline bool on_task_stack(struct task_struct *tsk, unsigned long sp,
+ unsigned long *stack_low,
+ unsigned long *stack_high)
{
unsigned long low = (unsigned long)task_stack_page(tsk);
unsigned long high = low + THREAD_SIZE;
- return (low <= sp && sp < high);
+ if (sp < low || sp >= high)
+ return false;
+
+ if (stack_low && stack_high) {
+ *stack_low = low;
+ *stack_high = high;
+ }
+
+ return true;
}
#ifdef CONFIG_VMAP_STACK
DECLARE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack);
-static inline bool on_overflow_stack(unsigned long sp)
+static inline bool on_overflow_stack(unsigned long sp,
+ unsigned long *stack_low,
+ unsigned long *stack_high)
{
unsigned long low = (unsigned long)raw_cpu_ptr(overflow_stack);
unsigned long high = low + OVERFLOW_STACK_SIZE;
- return (low <= sp && sp < high);
+ if (sp < low || sp >= high)
+ return false;
+
+ if (stack_low && stack_high) {
+ *stack_low = low;
+ *stack_high = high;
+ }
+
+ return true;
}
#else
-static inline bool on_overflow_stack(unsigned long sp) { return false; }
+static inline bool on_overflow_stack(unsigned long sp,
+ unsigned long *stack_low,
+ unsigned long *stack_high) { return false; }
#endif
+enum stack_type {
+ STACK_TYPE_UNKNOWN,
+ STACK_TYPE_TASK,
+ STACK_TYPE_IRQ,
+ STACK_TYPE_OVERFLOW,
+ STACK_TYPE_SDEI,
+};
+
+static inline enum stack_type current_stack_type(struct task_struct *tsk,
+ unsigned long sp,
+ unsigned long *stack_low,
+ unsigned long *stack_high)
+{
+ if (on_task_stack(tsk, sp, stack_low, stack_high))
+ return STACK_TYPE_TASK;
+ if (on_irq_stack(sp, stack_low, stack_high))
+ return STACK_TYPE_IRQ;
+ if (on_overflow_stack(sp, stack_low, stack_high))
+ return STACK_TYPE_OVERFLOW;
+ if (on_sdei_stack(sp, stack_low, stack_high))
+ return STACK_TYPE_SDEI;
+ return STACK_TYPE_UNKNOWN;
+}
+
/*
* We can only safely access per-cpu stacks from current in a non-preemptible
* context.
*/
static inline bool on_accessible_stack(struct task_struct *tsk, unsigned long sp)
{
- if (on_task_stack(tsk, sp))
+ enum stack_type type;
+ unsigned long low, high;
+
+ type = current_stack_type(tsk, sp, &low, &high);
+
+ switch (type) {
+ case STACK_TYPE_TASK:
return true;
- if (tsk != current || preemptible())
+ case STACK_TYPE_IRQ:
+ case STACK_TYPE_OVERFLOW:
+ case STACK_TYPE_SDEI:
+ if (tsk != current || preemptible())
+ return false;
+ else
+ return true;
+ case STACK_TYPE_UNKNOWN:
return false;
- if (on_irq_stack(sp))
- return true;
- if (on_overflow_stack(sp))
- return true;
- if (on_sdei_stack(sp))
- return true;
+ }
return false;
}
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 5c338ce5a7fa..a6b3a2be7561 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -132,7 +132,7 @@ static bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
{
return ((addr & ~(THREAD_SIZE - 1)) ==
(kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1))) ||
- on_irq_stack(addr);
+ on_irq_stack(addr, NULL, NULL);
}
/**
diff --git a/arch/arm64/kernel/sdei.c b/arch/arm64/kernel/sdei.c
index 6b8d90d5ceae..8e18913a53fd 100644
--- a/arch/arm64/kernel/sdei.c
+++ b/arch/arm64/kernel/sdei.c
@@ -88,7 +88,9 @@ static int init_sdei_stacks(void)
return err;
}
-bool _on_sdei_stack(unsigned long sp)
+bool _on_sdei_stack(unsigned long sp,
+ unsigned long *stack_low,
+ unsigned long *stack_high)
{
unsigned long low, high;
@@ -98,13 +100,26 @@ bool _on_sdei_stack(unsigned long sp)
low = (unsigned long)raw_cpu_read(sdei_stack_critical_ptr);
high = low + SDEI_STACK_SIZE;
- if (low <= sp && sp < high)
+ if (low <= sp && sp < high) {
+ if (stack_low && stack_high) {
+ *stack_low = low;
+ *stack_high = high;
+ }
return true;
+ }
low = (unsigned long)raw_cpu_read(sdei_stack_normal_ptr);
high = low + SDEI_STACK_SIZE;
- return (low <= sp && sp < high);
+ if (low <= sp && sp < high) {
+ if (stack_low && stack_high) {
+ *stack_low = low;
+ *stack_high = high;
+ }
+ return true;
+ }
+
+ return false;
}
unsigned long sdei_arch_get_entry_point(int conduit)
--
2.17.1
On Wed, Jul 18, 2018 at 2:10 PM, Laura Abbott <[email protected]> wrote:
>
> Implementation of stackleak based heavily on the x86 version
>
> Signed-off-by: Laura Abbott <[email protected]>
> ---
> Since last time: Minor style cleanups. Re-wrote check_alloca to
> correctly handle all stack types. While doing that, I also realized
> current_top_of_stack was incorrect so I fixed that as well.
Can you drop the include/linux/stackleak.h change from this series?
I've included that in the v14 in linux-next already, so that these
patches can land entirely separately in the arm64 tree (which was the
request).
Otherwise, this looks great!
Reviewed-by: Kees Cook <[email protected]>
-Kees
> ---
> arch/arm64/Kconfig | 1 +
> arch/arm64/include/asm/processor.h | 17 ++++++++++++++
> arch/arm64/kernel/entry.S | 7 ++++++
> arch/arm64/kernel/process.c | 32 +++++++++++++++++++++++++++
> arch/arm64/kvm/hyp/Makefile | 3 ++-
> drivers/firmware/efi/libstub/Makefile | 3 ++-
> include/linux/stackleak.h | 1 +
> 7 files changed, 62 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 42c090cf0292..216d36a49ab5 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -96,6 +96,7 @@ config ARM64
> select HAVE_ARCH_MMAP_RND_BITS
> select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPAT
> select HAVE_ARCH_SECCOMP_FILTER
> + select HAVE_ARCH_STACKLEAK
> select HAVE_ARCH_THREAD_STRUCT_WHITELIST
> select HAVE_ARCH_TRACEHOOK
> select HAVE_ARCH_TRANSPARENT_HUGEPAGE
> diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
> index a73ae1e49200..4f3062ee22c6 100644
> --- a/arch/arm64/include/asm/processor.h
> +++ b/arch/arm64/include/asm/processor.h
> @@ -266,5 +266,22 @@ extern void __init minsigstksz_setup(void);
> #define SVE_SET_VL(arg) sve_set_current_vl(arg)
> #define SVE_GET_VL() sve_get_current_vl()
>
> +/*
> + * For CONFIG_STACKLEAK
> + *
> + * These need to be macros because otherwise we get stuck in a nightmare
> + * of header definitions for the use of task_stack_page.
> + */
> +
> +#define current_top_of_stack() \
> +({ \
> + unsigned long _low = 0; \
> + unsigned long _high = 0; \
> + \
> + current_stack_type(current, current_stack_pointer, &_low, &_high); \
> + _high; \
> +})
> +#define on_thread_stack() (on_task_stack(current, current_stack_pointer, NULL, NULL))
> +
> #endif /* __ASSEMBLY__ */
> #endif /* __ASM_PROCESSOR_H */
> diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
> index 28ad8799406f..67d12016063d 100644
> --- a/arch/arm64/kernel/entry.S
> +++ b/arch/arm64/kernel/entry.S
> @@ -431,6 +431,11 @@ tsk .req x28 // current thread_info
>
> .text
>
> + .macro stackleak_erase
> +#ifdef CONFIG_GCC_PLUGIN_STACKLEAK
> + bl stackleak_erase
> +#endif
> + .endm
> /*
> * Exception vectors.
> */
> @@ -910,6 +915,7 @@ ret_fast_syscall:
> and x2, x1, #_TIF_WORK_MASK
> cbnz x2, work_pending
> enable_step_tsk x1, x2
> + stackleak_erase
> kernel_exit 0
> ret_fast_syscall_trace:
> enable_daif
> @@ -936,6 +942,7 @@ ret_to_user:
> cbnz x2, work_pending
> finish_ret_to_user:
> enable_step_tsk x1, x2
> + stackleak_erase
> kernel_exit 0
> ENDPROC(ret_to_user)
>
> diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
> index e10bc363f533..904defa36689 100644
> --- a/arch/arm64/kernel/process.c
> +++ b/arch/arm64/kernel/process.c
> @@ -493,3 +493,35 @@ void arch_setup_new_exec(void)
> {
> current->mm->context.flags = is_compat_task() ? MMCF_AARCH32 : 0;
> }
> +
> +#ifdef CONFIG_GCC_PLUGIN_STACKLEAK
> +void __used stackleak_check_alloca(unsigned long size)
> +{
> + unsigned long stack_left;
> + enum stack_type type;
> + unsigned long current_sp = current_stack_pointer;
> + unsigned long low, high;
> +
> + type = current_stack_type(current, current_sp, &low, &high);
> + BUG_ON(type == STACK_TYPE_UNKNOWN);
> +
> + stack_left = current_sp - low;
> +
> + if (size >= stack_left) {
> + /*
> + * Kernel stack depth overflow is detected, let's report that.
> + * If CONFIG_VMAP_STACK is enabled, we can safely use BUG().
> + * If CONFIG_VMAP_STACK is disabled, BUG() handling can corrupt
> + * the neighbour memory. CONFIG_SCHED_STACK_END_CHECK calls
> + * panic() in a similar situation, so let's do the same if that
> + * option is on. Otherwise just use BUG() and hope for the best.
> + */
> +#if !defined(CONFIG_VMAP_STACK) && defined(CONFIG_SCHED_STACK_END_CHECK)
> + panic("alloca() over the kernel stack boundary\n");
> +#else
> + BUG();
> +#endif
> + }
> +}
> +EXPORT_SYMBOL(stackleak_check_alloca);
> +#endif
> diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
> index 4313f7475333..2fabc2dc1966 100644
> --- a/arch/arm64/kvm/hyp/Makefile
> +++ b/arch/arm64/kvm/hyp/Makefile
> @@ -3,7 +3,8 @@
> # Makefile for Kernel-based Virtual Machine module, HYP part
> #
>
> -ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING
> +ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING \
> + $(DISABLE_STACKLEAK_PLUGIN)
>
> KVM=../../../../virt/kvm
>
> diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
> index a34e9290a699..25dd2a14560d 100644
> --- a/drivers/firmware/efi/libstub/Makefile
> +++ b/drivers/firmware/efi/libstub/Makefile
> @@ -20,7 +20,8 @@ cflags-$(CONFIG_EFI_ARMSTUB) += -I$(srctree)/scripts/dtc/libfdt
> KBUILD_CFLAGS := $(cflags-y) -DDISABLE_BRANCH_PROFILING \
> -D__NO_FORTIFY \
> $(call cc-option,-ffreestanding) \
> - $(call cc-option,-fno-stack-protector)
> + $(call cc-option,-fno-stack-protector) \
> + $(DISABLE_STACKLEAK_PLUGIN)
>
> GCOV_PROFILE := n
> KASAN_SANITIZE := n
> diff --git a/include/linux/stackleak.h b/include/linux/stackleak.h
> index b911b973d328..08420ec6b7c3 100644
> --- a/include/linux/stackleak.h
> +++ b/include/linux/stackleak.h
> @@ -5,6 +5,7 @@
> #include <linux/sched.h>
> #include <linux/sched/task_stack.h>
>
> +#include <asm/stacktrace.h>
> /*
> * Check that the poison value points to the unused hole in the
> * virtual memory map for your platform.
> --
> 2.17.1
>
--
Kees Cook
Pixel Security
Hello Laura,
Thanks again for your work.
Please see some comments below.
On 19.07.2018 00:10, Laura Abbott wrote:
> Implementation of stackleak based heavily on the x86 version
>
> Signed-off-by: Laura Abbott <[email protected]>
> ---
> Since last time: Minor style cleanups. Re-wrote check_alloca to
> correctly handle all stack types. While doing that, I also realized
> current_top_of_stack was incorrect so I fixed that as well.
> ---
> arch/arm64/Kconfig | 1 +
> arch/arm64/include/asm/processor.h | 17 ++++++++++++++
> arch/arm64/kernel/entry.S | 7 ++++++
> arch/arm64/kernel/process.c | 32 +++++++++++++++++++++++++++
> arch/arm64/kvm/hyp/Makefile | 3 ++-
> drivers/firmware/efi/libstub/Makefile | 3 ++-
> include/linux/stackleak.h | 1 +
> 7 files changed, 62 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 42c090cf0292..216d36a49ab5 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -96,6 +96,7 @@ config ARM64
> select HAVE_ARCH_MMAP_RND_BITS
> select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPAT
> select HAVE_ARCH_SECCOMP_FILTER
> + select HAVE_ARCH_STACKLEAK
> select HAVE_ARCH_THREAD_STRUCT_WHITELIST
> select HAVE_ARCH_TRACEHOOK
> select HAVE_ARCH_TRANSPARENT_HUGEPAGE
> diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
> index a73ae1e49200..4f3062ee22c6 100644
> --- a/arch/arm64/include/asm/processor.h
> +++ b/arch/arm64/include/asm/processor.h
> @@ -266,5 +266,22 @@ extern void __init minsigstksz_setup(void);
> #define SVE_SET_VL(arg) sve_set_current_vl(arg)
> #define SVE_GET_VL() sve_get_current_vl()
>
> +/*
> + * For CONFIG_STACKLEAK
Our config option is called CONFIG_GCC_PLUGIN_STACKLEAK.
> + *
> + * These need to be macros because otherwise we get stuck in a nightmare
> + * of header definitions for the use of task_stack_page.
> + */
> +
> +#define current_top_of_stack() \
> +({ \
> + unsigned long _low = 0; \
> + unsigned long _high = 0; \
> + \
> + current_stack_type(current, current_stack_pointer, &_low, &_high); \
> + _high; \
> +})
Do you really need _low here? Ah, I see this in the previous patch:
+ if (stack_low && stack_high) {
+ *stack_low = low;
+ *stack_high = high;
+ }
How about checking them against NULL separately? That would allow
+ current_stack_type(current, current_stack_pointer, NULL, &_high);
Also a minor comment - how about aligning backslashes?
> +#define on_thread_stack() (on_task_stack(current, current_stack_pointer, NULL, NULL))
> +
> #endif /* __ASSEMBLY__ */
> #endif /* __ASM_PROCESSOR_H */
> diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
> index 28ad8799406f..67d12016063d 100644
> --- a/arch/arm64/kernel/entry.S
> +++ b/arch/arm64/kernel/entry.S
> @@ -431,6 +431,11 @@ tsk .req x28 // current thread_info
>
> .text
>
> + .macro stackleak_erase
> +#ifdef CONFIG_GCC_PLUGIN_STACKLEAK
> + bl stackleak_erase
> +#endif
> + .endm
> /*
> * Exception vectors.
> */
> @@ -910,6 +915,7 @@ ret_fast_syscall:
> and x2, x1, #_TIF_WORK_MASK
> cbnz x2, work_pending
> enable_step_tsk x1, x2
> + stackleak_erase
> kernel_exit 0
> ret_fast_syscall_trace:
> enable_daif
> @@ -936,6 +942,7 @@ ret_to_user:
> cbnz x2, work_pending
> finish_ret_to_user:
> enable_step_tsk x1, x2
> + stackleak_erase
> kernel_exit 0
> ENDPROC(ret_to_user)
>
> diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
> index e10bc363f533..904defa36689 100644
> --- a/arch/arm64/kernel/process.c
> +++ b/arch/arm64/kernel/process.c
> @@ -493,3 +493,35 @@ void arch_setup_new_exec(void)
> {
> current->mm->context.flags = is_compat_task() ? MMCF_AARCH32 : 0;
> }
> +
> +#ifdef CONFIG_GCC_PLUGIN_STACKLEAK
> +void __used stackleak_check_alloca(unsigned long size)
> +{
> + unsigned long stack_left;
> + enum stack_type type;
> + unsigned long current_sp = current_stack_pointer;
> + unsigned long low, high;
> +
> + type = current_stack_type(current, current_sp, &low, &high);
> + BUG_ON(type == STACK_TYPE_UNKNOWN);
> +
> + stack_left = current_sp - low;
> +
> + if (size >= stack_left) {
> + /*
> + * Kernel stack depth overflow is detected, let's report that.
> + * If CONFIG_VMAP_STACK is enabled, we can safely use BUG().
> + * If CONFIG_VMAP_STACK is disabled, BUG() handling can corrupt
> + * the neighbour memory. CONFIG_SCHED_STACK_END_CHECK calls
> + * panic() in a similar situation, so let's do the same if that
> + * option is on. Otherwise just use BUG() and hope for the best.
> + */
> +#if !defined(CONFIG_VMAP_STACK) && defined(CONFIG_SCHED_STACK_END_CHECK)
> + panic("alloca() over the kernel stack boundary\n");
> +#else
> + BUG();
> +#endif
This comment and #if logic should be dropped, we should always use panic() here
on arm64. Mark Rutland and I have worked out the solution for arm64 in this thread:
http://openwall.com/lists/kernel-hardening/2018/05/11/12
Rationale: on arm64 with CONFIG_VMAP_STACK, a stack overflow results in panic()
anyway.
> + }
> +}
> +EXPORT_SYMBOL(stackleak_check_alloca);
> +#endif
> diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
> index 4313f7475333..2fabc2dc1966 100644
> --- a/arch/arm64/kvm/hyp/Makefile
> +++ b/arch/arm64/kvm/hyp/Makefile
> @@ -3,7 +3,8 @@
> # Makefile for Kernel-based Virtual Machine module, HYP part
> #
>
> -ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING
> +ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING \
> + $(DISABLE_STACKLEAK_PLUGIN)
>
> KVM=../../../../virt/kvm
>
> diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
> index a34e9290a699..25dd2a14560d 100644
> --- a/drivers/firmware/efi/libstub/Makefile
> +++ b/drivers/firmware/efi/libstub/Makefile
> @@ -20,7 +20,8 @@ cflags-$(CONFIG_EFI_ARMSTUB) += -I$(srctree)/scripts/dtc/libfdt
> KBUILD_CFLAGS := $(cflags-y) -DDISABLE_BRANCH_PROFILING \
> -D__NO_FORTIFY \
> $(call cc-option,-ffreestanding) \
> - $(call cc-option,-fno-stack-protector)
> + $(call cc-option,-fno-stack-protector) \
> + $(DISABLE_STACKLEAK_PLUGIN)
>
> GCOV_PROFILE := n
> KASAN_SANITIZE := n
> diff --git a/include/linux/stackleak.h b/include/linux/stackleak.h
> index b911b973d328..08420ec6b7c3 100644
> --- a/include/linux/stackleak.h
> +++ b/include/linux/stackleak.h
> @@ -5,6 +5,7 @@
> #include <linux/sched.h>
> #include <linux/sched/task_stack.h>
>
> +#include <asm/stacktrace.h>
> /*
> * Check that the poison value points to the unused hole in the
> * virtual memory map for your platform.
>
Hi Laura,
On Wed, Jul 18, 2018 at 02:10:12PM -0700, Laura Abbott wrote:
>
> In preparation for enabling the stackleak plugin on arm64,
> we need a way to get the bounds of the current stack.
> Introduce a new primitive current_stack_type which is similar
> to x86's get_stack_info. Utilize that to rework
> on_accessible_stack slightly as well.
>
> Signed-off-by: Laura Abbott <[email protected]>
> ---
> So this did end up looking quite a bit like get_stack_info but I didn't
> really see the need to integrate this more than this. I do think
> actually enumerating the types makes things a bit cleaner.
> ---
> arch/arm64/include/asm/sdei.h | 8 ++-
> arch/arm64/include/asm/stacktrace.h | 94 ++++++++++++++++++++++++-----
> arch/arm64/kernel/ptrace.c | 2 +-
> arch/arm64/kernel/sdei.c | 21 ++++++-
> 4 files changed, 103 insertions(+), 22 deletions(-)
>
> diff --git a/arch/arm64/include/asm/sdei.h b/arch/arm64/include/asm/sdei.h
> index e073e6886685..34f7b203845b 100644
> --- a/arch/arm64/include/asm/sdei.h
> +++ b/arch/arm64/include/asm/sdei.h
> @@ -40,15 +40,17 @@ asmlinkage unsigned long __sdei_handler(struct pt_regs *regs,
> unsigned long sdei_arch_get_entry_point(int conduit);
> #define sdei_arch_get_entry_point(x) sdei_arch_get_entry_point(x)
>
> -bool _on_sdei_stack(unsigned long sp);
> -static inline bool on_sdei_stack(unsigned long sp)
> +bool _on_sdei_stack(unsigned long sp, unsigned long *, unsigned long *);
> +static inline bool on_sdei_stack(unsigned long sp,
> + unsigned long *stack_low,
> + unsigned long *stack_high)
> {
> if (!IS_ENABLED(CONFIG_VMAP_STACK))
> return false;
> if (!IS_ENABLED(CONFIG_ARM_SDE_INTERFACE))
> return false;
> if (in_nmi())
> - return _on_sdei_stack(sp);
> + return _on_sdei_stack(sp, stack_low, stack_high);
>
> return false;
> }
> diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h
> index 902f9edacbea..9855a0425e64 100644
> --- a/arch/arm64/include/asm/stacktrace.h
> +++ b/arch/arm64/include/asm/stacktrace.h
> @@ -39,7 +39,9 @@ extern void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk);
>
> DECLARE_PER_CPU(unsigned long *, irq_stack_ptr);
>
> -static inline bool on_irq_stack(unsigned long sp)
> +static inline bool on_irq_stack(unsigned long sp,
> + unsigned long *stack_low,
> + unsigned long *stack_high)
> {
> unsigned long low = (unsigned long)raw_cpu_read(irq_stack_ptr);
> unsigned long high = low + IRQ_STACK_SIZE;
> @@ -47,47 +49,109 @@ static inline bool on_irq_stack(unsigned long sp)
> if (!low)
> return false;
>
> - return (low <= sp && sp < high);
> + if (sp < low || sp >= high)
> + return false;
> +
> + if (stack_low && stack_high) {
> + *stack_low = low;
> + *stack_high = high;
> + }
> +
> + return true;
> }
Rather than having to pass separete pointers to low/high, could we
please wrap them up as a struct, e.g.
struct stack_info {
unsigned long low, high;
stack_type type;
}
... and pass a single pointer to that? e.g.
static inline bool on_irq_stack(unsigned long sp, struct stack_info *info)
{
unsigned long low = (unsigned long)raw_cpu_read(irq_stack_ptr);
unsigned long high = low + IRQ_STACK_SIZE;
if (!low)
return false;
if (sp < low || sp >= high)
return false;
if (info) {
info->low = low;
info->high = high;
info->type = STACK_TYPE_IRQ;
}
return true;
}
That simplified the prototypes, and will allow us to distinguish the two
SDEI stacks (which we'll need for making stack unwiding robust to
cross-stack loops).
> -static inline bool on_task_stack(struct task_struct *tsk, unsigned long sp)
> +static inline bool on_task_stack(struct task_struct *tsk, unsigned long sp,
> + unsigned long *stack_low,
> + unsigned long *stack_high)
> {
> unsigned long low = (unsigned long)task_stack_page(tsk);
> unsigned long high = low + THREAD_SIZE;
>
> - return (low <= sp && sp < high);
> + if (sp < low || sp >= high)
> + return false;
> +
> + if (stack_low && stack_high) {
> + *stack_low = low;
> + *stack_high = high;
> + }
> +
> + return true;
> }
>
> #ifdef CONFIG_VMAP_STACK
> DECLARE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack);
>
> -static inline bool on_overflow_stack(unsigned long sp)
> +static inline bool on_overflow_stack(unsigned long sp,
> + unsigned long *stack_low,
> + unsigned long *stack_high)
> {
> unsigned long low = (unsigned long)raw_cpu_ptr(overflow_stack);
> unsigned long high = low + OVERFLOW_STACK_SIZE;
>
> - return (low <= sp && sp < high);
> + if (sp < low || sp >= high)
> + return false;
> +
> + if (stack_low && stack_high) {
> + *stack_low = low;
> + *stack_high = high;
> + }
> +
> + return true;
> }
> #else
> -static inline bool on_overflow_stack(unsigned long sp) { return false; }
> +static inline bool on_overflow_stack(unsigned long sp,
> + unsigned long *stack_low,
> + unsigned long *stack_high) { return false; }
> #endif
>
> +enum stack_type {
> + STACK_TYPE_UNKNOWN,
> + STACK_TYPE_TASK,
> + STACK_TYPE_IRQ,
> + STACK_TYPE_OVERFLOW,
> + STACK_TYPE_SDEI,
> +};
For SDEI we'll need STACK_TYPE_SDEI_NORMAL and STACK_TYPE_SDEI_CRITICAL,
at least for stack unwinding.
> +
> +static inline enum stack_type current_stack_type(struct task_struct *tsk,
> + unsigned long sp,
> + unsigned long *stack_low,
> + unsigned long *stack_high)
> +{
> + if (on_task_stack(tsk, sp, stack_low, stack_high))
> + return STACK_TYPE_TASK;
> + if (on_irq_stack(sp, stack_low, stack_high))
> + return STACK_TYPE_IRQ;
> + if (on_overflow_stack(sp, stack_low, stack_high))
> + return STACK_TYPE_OVERFLOW;
> + if (on_sdei_stack(sp, stack_low, stack_high))
> + return STACK_TYPE_SDEI;
> + return STACK_TYPE_UNKNOWN;
> +}
> +
> /*
> * We can only safely access per-cpu stacks from current in a non-preemptible
> * context.
> */
> static inline bool on_accessible_stack(struct task_struct *tsk, unsigned long sp)
> {
> - if (on_task_stack(tsk, sp))
> + enum stack_type type;
> + unsigned long low, high;
> +
> + type = current_stack_type(tsk, sp, &low, &high);
> +
> + switch (type) {
> + case STACK_TYPE_TASK:
> return true;
> - if (tsk != current || preemptible())
> + case STACK_TYPE_IRQ:
> + case STACK_TYPE_OVERFLOW:
> + case STACK_TYPE_SDEI:
> + if (tsk != current || preemptible())
> + return false;
> + else
> + return true;
> + case STACK_TYPE_UNKNOWN:
> return false;
> - if (on_irq_stack(sp))
> - return true;
> - if (on_overflow_stack(sp))
> - return true;
> - if (on_sdei_stack(sp))
> - return true;
> + }
>
> return false;
> }
With the stacut stack_info, I think we can leave the logic of
on_accessible_stack() as-is, modulo a new info parameter that we pass on
into each on_<foo>_stack(), and then we don't neeed a separate
current_stack_type() function.
> diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
> index 5c338ce5a7fa..a6b3a2be7561 100644
> --- a/arch/arm64/kernel/ptrace.c
> +++ b/arch/arm64/kernel/ptrace.c
> @@ -132,7 +132,7 @@ static bool regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
> {
> return ((addr & ~(THREAD_SIZE - 1)) ==
> (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1))) ||
> - on_irq_stack(addr);
> + on_irq_stack(addr, NULL, NULL);
> }
>
> /**
> diff --git a/arch/arm64/kernel/sdei.c b/arch/arm64/kernel/sdei.c
> index 6b8d90d5ceae..8e18913a53fd 100644
> --- a/arch/arm64/kernel/sdei.c
> +++ b/arch/arm64/kernel/sdei.c
> @@ -88,7 +88,9 @@ static int init_sdei_stacks(void)
> return err;
> }
>
> -bool _on_sdei_stack(unsigned long sp)
> +bool _on_sdei_stack(unsigned long sp,
> + unsigned long *stack_low,
> + unsigned long *stack_high)
> {
> unsigned long low, high;
>
> @@ -98,13 +100,26 @@ bool _on_sdei_stack(unsigned long sp)
> low = (unsigned long)raw_cpu_read(sdei_stack_critical_ptr);
> high = low + SDEI_STACK_SIZE;
>
> - if (low <= sp && sp < high)
> + if (low <= sp && sp < high) {
> + if (stack_low && stack_high) {
> + *stack_low = low;
> + *stack_high = high;
> + }
> return true;
> + }
>
> low = (unsigned long)raw_cpu_read(sdei_stack_normal_ptr);
> high = low + SDEI_STACK_SIZE;
>
> - return (low <= sp && sp < high);
> + if (low <= sp && sp < high) {
> + if (stack_low && stack_high) {
> + *stack_low = low;
> + *stack_high = high;
> + }
> + return true;
> + }
> +
> + return false;
> }
We should probably split this into separate on_sdei_normal_stack() and
on_sdei_critical_stack() functions.
Then we can do:
bool on_sdei_<foo>_stack(...)
{
if (<out of bounds>)
return false;
if (info) {
<assign info fields>;
}
return true;
}
bool _on_sdei_stack(unsigned long sp, struct stack_info *info)
{
if (on_sedi_critical_stack(sp, info))
return true;
if (on_sdei_normal_stack(sp, info))
return true;
return false;
}
... which is a little nicer for legibility.
Otherwise, this looks good to me.
Thanks,
Mark.
On Wed, Jul 18, 2018 at 02:10:13PM -0700, Laura Abbott wrote:
>
> Implementation of stackleak based heavily on the x86 version
>
> Signed-off-by: Laura Abbott <[email protected]>
> ---
> Since last time: Minor style cleanups. Re-wrote check_alloca to
> correctly handle all stack types. While doing that, I also realized
> current_top_of_stack was incorrect so I fixed that as well.
> ---
> arch/arm64/Kconfig | 1 +
> arch/arm64/include/asm/processor.h | 17 ++++++++++++++
> arch/arm64/kernel/entry.S | 7 ++++++
> arch/arm64/kernel/process.c | 32 +++++++++++++++++++++++++++
> arch/arm64/kvm/hyp/Makefile | 3 ++-
> drivers/firmware/efi/libstub/Makefile | 3 ++-
> include/linux/stackleak.h | 1 +
> 7 files changed, 62 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index 42c090cf0292..216d36a49ab5 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -96,6 +96,7 @@ config ARM64
> select HAVE_ARCH_MMAP_RND_BITS
> select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPAT
> select HAVE_ARCH_SECCOMP_FILTER
> + select HAVE_ARCH_STACKLEAK
> select HAVE_ARCH_THREAD_STRUCT_WHITELIST
> select HAVE_ARCH_TRACEHOOK
> select HAVE_ARCH_TRANSPARENT_HUGEPAGE
> diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
> index a73ae1e49200..4f3062ee22c6 100644
> --- a/arch/arm64/include/asm/processor.h
> +++ b/arch/arm64/include/asm/processor.h
> @@ -266,5 +266,22 @@ extern void __init minsigstksz_setup(void);
> #define SVE_SET_VL(arg) sve_set_current_vl(arg)
> #define SVE_GET_VL() sve_get_current_vl()
>
> +/*
> + * For CONFIG_STACKLEAK
> + *
> + * These need to be macros because otherwise we get stuck in a nightmare
> + * of header definitions for the use of task_stack_page.
> + */
> +
> +#define current_top_of_stack() \
> +({ \
> + unsigned long _low = 0; \
> + unsigned long _high = 0; \
> + \
> + current_stack_type(current, current_stack_pointer, &_low, &_high); \
> + _high; \
> +})
... with the info changes, this could be:
#define current_top_of_stack() \
({ \
struct stack_info _info; \
BUG_ON(!on_accessible_stack(current_stack_pinter, &_info)); \
_info->high; \
})
> +#define on_thread_stack() (on_task_stack(current, current_stack_pointer, NULL, NULL))
... and one fewer NULL here.
> +
> #endif /* __ASSEMBLY__ */
> #endif /* __ASM_PROCESSOR_H */
> diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
> index 28ad8799406f..67d12016063d 100644
> --- a/arch/arm64/kernel/entry.S
> +++ b/arch/arm64/kernel/entry.S
> @@ -431,6 +431,11 @@ tsk .req x28 // current thread_info
>
> .text
>
> + .macro stackleak_erase
> +#ifdef CONFIG_GCC_PLUGIN_STACKLEAK
> + bl stackleak_erase
> +#endif
> + .endm
> /*
> * Exception vectors.
> */
> @@ -910,6 +915,7 @@ ret_fast_syscall:
> and x2, x1, #_TIF_WORK_MASK
> cbnz x2, work_pending
> enable_step_tsk x1, x2
> + stackleak_erase
> kernel_exit 0
> ret_fast_syscall_trace:
> enable_daif
> @@ -936,6 +942,7 @@ ret_to_user:
> cbnz x2, work_pending
> finish_ret_to_user:
> enable_step_tsk x1, x2
> + stackleak_erase
> kernel_exit 0
> ENDPROC(ret_to_user)
>
> diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
> index e10bc363f533..904defa36689 100644
> --- a/arch/arm64/kernel/process.c
> +++ b/arch/arm64/kernel/process.c
> @@ -493,3 +493,35 @@ void arch_setup_new_exec(void)
> {
> current->mm->context.flags = is_compat_task() ? MMCF_AARCH32 : 0;
> }
> +
> +#ifdef CONFIG_GCC_PLUGIN_STACKLEAK
> +void __used stackleak_check_alloca(unsigned long size)
> +{
> + unsigned long stack_left;
> + enum stack_type type;
> + unsigned long current_sp = current_stack_pointer;
> + unsigned long low, high;
> +
> + type = current_stack_type(current, current_sp, &low, &high);
> + BUG_ON(type == STACK_TYPE_UNKNOWN);
> +
> + stack_left = current_sp - low;
... similarly with the info changes, this could be:
unsigned long current_sp = current_stack_pointer;
unsigned long stack_left;
struct stack_info info;
BUG_ON(!on_accessible_stack(current, current_sp, &info));
stack_lead = current_sp - info->low;
Otherwise, this looks good to me.
Thanks,
Mark.
> +
> + if (size >= stack_left) {
> + /*
> + * Kernel stack depth overflow is detected, let's report that.
> + * If CONFIG_VMAP_STACK is enabled, we can safely use BUG().
> + * If CONFIG_VMAP_STACK is disabled, BUG() handling can corrupt
> + * the neighbour memory. CONFIG_SCHED_STACK_END_CHECK calls
> + * panic() in a similar situation, so let's do the same if that
> + * option is on. Otherwise just use BUG() and hope for the best.
> + */
> +#if !defined(CONFIG_VMAP_STACK) && defined(CONFIG_SCHED_STACK_END_CHECK)
> + panic("alloca() over the kernel stack boundary\n");
> +#else
> + BUG();
> +#endif
> + }
> +}
> +EXPORT_SYMBOL(stackleak_check_alloca);
> +#endif
> diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
> index 4313f7475333..2fabc2dc1966 100644
> --- a/arch/arm64/kvm/hyp/Makefile
> +++ b/arch/arm64/kvm/hyp/Makefile
> @@ -3,7 +3,8 @@
> # Makefile for Kernel-based Virtual Machine module, HYP part
> #
>
> -ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING
> +ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING \
> + $(DISABLE_STACKLEAK_PLUGIN)
>
> KVM=../../../../virt/kvm
>
> diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
> index a34e9290a699..25dd2a14560d 100644
> --- a/drivers/firmware/efi/libstub/Makefile
> +++ b/drivers/firmware/efi/libstub/Makefile
> @@ -20,7 +20,8 @@ cflags-$(CONFIG_EFI_ARMSTUB) += -I$(srctree)/scripts/dtc/libfdt
> KBUILD_CFLAGS := $(cflags-y) -DDISABLE_BRANCH_PROFILING \
> -D__NO_FORTIFY \
> $(call cc-option,-ffreestanding) \
> - $(call cc-option,-fno-stack-protector)
> + $(call cc-option,-fno-stack-protector) \
> + $(DISABLE_STACKLEAK_PLUGIN)
>
> GCOV_PROFILE := n
> KASAN_SANITIZE := n
> diff --git a/include/linux/stackleak.h b/include/linux/stackleak.h
> index b911b973d328..08420ec6b7c3 100644
> --- a/include/linux/stackleak.h
> +++ b/include/linux/stackleak.h
> @@ -5,6 +5,7 @@
> #include <linux/sched.h>
> #include <linux/sched/task_stack.h>
>
> +#include <asm/stacktrace.h>
> /*
> * Check that the poison value points to the unused hole in the
> * virtual memory map for your platform.
> --
> 2.17.1
>