* [RFC PATCH] riscv: add VMAP_STACK overflow detection
@ 2021-05-07 9:25 ` Tong Tiangen
0 siblings, 0 replies; 9+ messages in thread
From: Tong Tiangen @ 2021-05-07 9:25 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou
Cc: linux-riscv, linux-kernel, Tong Tiangen
This patch adds stack overflow detection to riscv, usable when
CONFIG_VMAP_STACK=y.
Overflow is detected in kernel exception entry(kernel/entry.S), if the kernel
stack is overflow and been detected, the overflow handler is invoked on a
per-cpu overflow stack. This approach preserves GPRs and the original exception
information.
The overflow detect is performed before any attempt is made to access the stack
and the principle of stack overflow detection: kernel stacks are aligned to
double their size, enabling overflow to be detected with a single bit test. For
example, a 16K stack is aligned to 32K, ensuring that bit 14 of the SP must be
zero. On an overflow (or underflow), this bit is flipped. Thus, overflow (of
less than the size of the stack) can be detected by testing whether this bit is
set.
This gives us a useful error message on stack overflow, as can be trigger with
the LKDTM overflow test:
[ 388.053267] lkdtm: Performing direct entry EXHAUST_STACK
[ 388.053663] lkdtm: Calling function with 1024 frame size to depth 32 ...
[ 388.054016] lkdtm: loop 32/32 ...
[ 388.054186] lkdtm: loop 31/32 ...
[ 388.054491] lkdtm: loop 30/32 ...
[ 388.054672] lkdtm: loop 29/32 ...
[ 388.054859] lkdtm: loop 28/32 ...
[ 388.055010] lkdtm: loop 27/32 ...
[ 388.055163] lkdtm: loop 26/32 ...
[ 388.055309] lkdtm: loop 25/32 ...
[ 388.055481] lkdtm: loop 24/32 ...
[ 388.055653] lkdtm: loop 23/32 ...
[ 388.055837] lkdtm: loop 22/32 ...
[ 388.056015] lkdtm: loop 21/32 ...
[ 388.056188] lkdtm: loop 20/32 ...
[ 388.058145] Insufficient stack space to handle exception!
[ 388.058153] Task stack: [0xffffffd014260000..0xffffffd014264000]
[ 388.058160] Overflow stack: [0xffffffe1f8d2c220..0xffffffe1f8d2d220]
[ 388.058168] CPU: 0 PID: 89 Comm: bash Not tainted 5.12.0-rc8-dirty #90
[ 388.058175] Hardware name: riscv-virtio,qemu (DT)
[ 388.058187] epc : number+0x32/0x2c0
[ 388.058247] ra : vsnprintf+0x2ae/0x3f0
[ 388.058255] epc : ffffffe0002d38f6 ra : ffffffe0002d814e sp : ffffffd01425ffc0
[ 388.058263] gp : ffffffe0012e4010 tp : ffffffe08014da00 t0 : ffffffd0142606e8
[ 388.058271] t1 : 0000000000000000 t2 : 0000000000000000 s0 : ffffffd014260070
[ 388.058303] s1 : ffffffd014260158 a0 : ffffffd01426015e a1 : ffffffd014260158
[ 388.058311] a2 : 0000000000000013 a3 : ffff0a01ffffff10 a4 : ffffffe000c398e0
[ 388.058319] a5 : 511b02ec65f3e300 a6 : 0000000000a1749a a7 : 0000000000000000
[ 388.058327] s2 : ffffffff000000ff s3 : 00000000ffff0a01 s4 : ffffffe0012e50a8
[ 388.058335] s5 : 0000000000ffff0a s6 : ffffffe0012e50a8 s7 : ffffffe000da1cc0
[ 388.058343] s8 : ffffffffffffffff s9 : ffffffd0142602b0 s10: ffffffd0142602a8
[ 388.058351] s11: ffffffd01426015e t3 : 00000000000f0000 t4 : ffffffffffffffff
[ 388.058359] t5 : 000000000000002f t6 : ffffffd014260158
[ 388.058366] status: 0000000000000100 badaddr: ffffffd01425fff8 cause: 000000000000000f
[ 388.058374] Kernel panic - not syncing: Kernel stack overflow
[ 388.058381] CPU: 0 PID: 89 Comm: bash Not tainted 5.12.0-rc8-dirty #90
[ 388.058387] Hardware name: riscv-virtio,qemu (DT)
[ 388.058393] Call Trace:
[ 388.058400] [<ffffffe000004944>] walk_stackframe+0x0/0xce
[ 388.058406] [<ffffffe0006f0b28>] dump_backtrace+0x38/0x46
[ 388.058412] [<ffffffe0006f0b46>] show_stack+0x10/0x18
[ 388.058418] [<ffffffe0006f3690>] dump_stack+0x74/0x8e
[ 388.058424] [<ffffffe0006f0d52>] panic+0xfc/0x2b2
[ 388.058430] [<ffffffe0006f0acc>] print_trace_address+0x0/0x24
[ 388.058436] [<ffffffe0002d814e>] vsnprintf+0x2ae/0x3f0
[ 388.058956] SMP: stopping secondary CPUs
Signed-off-by: Tong Tiangen <tongtiangen@huawei.com>
---
arch/riscv/Kconfig | 1 +
arch/riscv/include/asm/thread_info.h | 15 ++++
arch/riscv/kernel/entry.S | 108 +++++++++++++++++++++++++++
arch/riscv/kernel/traps.c | 35 +++++++++
4 files changed, 159 insertions(+)
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 4515a10c5d22..587f001e84f4 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -63,6 +63,7 @@ config RISCV
select HAVE_ARCH_MMAP_RND_BITS if MMU
select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_TRACEHOOK
+ select HAVE_ARCH_VMAP_STACK
select HAVE_ASM_MODVERSIONS
select HAVE_CONTEXT_TRACKING
select HAVE_DEBUG_KMEMLEAK
diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h
index 0e549a3089b3..60da0dcacf14 100644
--- a/arch/riscv/include/asm/thread_info.h
+++ b/arch/riscv/include/asm/thread_info.h
@@ -19,6 +19,21 @@
#endif
#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
+/*
+ * By aligning VMAP'd stacks to 2 * THREAD_SIZE, we can detect overflow by
+ * checking sp & (1 << THREAD_SHIFT), which we can do cheaply in the entry
+ * assembly.
+ */
+#ifdef CONFIG_VMAP_STACK
+#define THREAD_ALIGN (2 * THREAD_SIZE)
+#else
+#define THREAD_ALIGN THREAD_SIZE
+#endif
+
+#define THREAD_SHIFT (PAGE_SHIFT + THREAD_SIZE_ORDER)
+#define OVERFLOW_STACK_SIZE SZ_4K
+#define SHADOW_OVERFLOW_STACK_SIZE (1024)
+
#ifndef __ASSEMBLY__
#include <asm/processor.h>
diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
index 83095faa680e..deadf4000b86 100644
--- a/arch/riscv/kernel/entry.S
+++ b/arch/riscv/kernel/entry.S
@@ -29,6 +29,15 @@ ENTRY(handle_exception)
_restore_kernel_tpsp:
csrr tp, CSR_SCRATCH
REG_S sp, TASK_TI_KERNEL_SP(tp)
+
+#ifdef CONFIG_VMAP_STACK
+ addi sp, sp, -(PT_SIZE_ON_STACK)
+ srli sp, sp, THREAD_SHIFT
+ andi sp, sp, 0x1
+ bnez sp, handle_kernel_stack_overflow
+ REG_L sp, TASK_TI_KERNEL_SP(tp)
+#endif
+
_save_context:
REG_S sp, TASK_TI_USER_SP(tp)
REG_L sp, TASK_TI_KERNEL_SP(tp)
@@ -375,6 +384,105 @@ handle_syscall_trace_exit:
call do_syscall_trace_exit
j ret_from_exception
+#ifdef CONFIG_VMAP_STACK
+handle_kernel_stack_overflow:
+ la sp, shadow_stack
+ addi sp, sp, SHADOW_OVERFLOW_STACK_SIZE
+
+ //save caller register to shadow stack
+ addi sp, sp, -(PT_SIZE_ON_STACK)
+ REG_S x1, PT_RA(sp)
+ REG_S x5, PT_T0(sp)
+ REG_S x6, PT_T1(sp)
+ REG_S x7, PT_T2(sp)
+ REG_S x10, PT_A0(sp)
+ REG_S x11, PT_A1(sp)
+ REG_S x12, PT_A2(sp)
+ REG_S x13, PT_A3(sp)
+ REG_S x14, PT_A4(sp)
+ REG_S x15, PT_A5(sp)
+ REG_S x16, PT_A6(sp)
+ REG_S x17, PT_A7(sp)
+ REG_S x28, PT_T3(sp)
+ REG_S x29, PT_T4(sp)
+ REG_S x30, PT_T5(sp)
+ REG_S x31, PT_T6(sp)
+
+ la ra, restore_caller_reg
+ tail get_overflow_stack
+
+restore_caller_reg:
+ //save per-cpu overflow stack
+ sd a0, -8(sp)
+ //restore caller register from shadow_stack
+ REG_L x1, PT_RA(sp)
+ REG_L x5, PT_T0(sp)
+ REG_L x6, PT_T1(sp)
+ REG_L x7, PT_T2(sp)
+ REG_L x10, PT_A0(sp)
+ REG_L x11, PT_A1(sp)
+ REG_L x12, PT_A2(sp)
+ REG_L x13, PT_A3(sp)
+ REG_L x14, PT_A4(sp)
+ REG_L x15, PT_A5(sp)
+ REG_L x16, PT_A6(sp)
+ REG_L x17, PT_A7(sp)
+ REG_L x28, PT_T3(sp)
+ REG_L x29, PT_T4(sp)
+ REG_L x30, PT_T5(sp)
+ REG_L x31, PT_T6(sp)
+
+ //load per-cpu overflow stack
+ ld sp, -8(sp)
+ addi sp, sp, -(PT_SIZE_ON_STACK)
+
+ //save context to overflow stack
+ REG_S x1, PT_RA(sp)
+ REG_S x3, PT_GP(sp)
+ REG_S x5, PT_T0(sp)
+ REG_S x6, PT_T1(sp)
+ REG_S x7, PT_T2(sp)
+ REG_S x8, PT_S0(sp)
+ REG_S x9, PT_S1(sp)
+ REG_S x10, PT_A0(sp)
+ REG_S x11, PT_A1(sp)
+ REG_S x12, PT_A2(sp)
+ REG_S x13, PT_A3(sp)
+ REG_S x14, PT_A4(sp)
+ REG_S x15, PT_A5(sp)
+ REG_S x16, PT_A6(sp)
+ REG_S x17, PT_A7(sp)
+ REG_S x18, PT_S2(sp)
+ REG_S x19, PT_S3(sp)
+ REG_S x20, PT_S4(sp)
+ REG_S x21, PT_S5(sp)
+ REG_S x22, PT_S6(sp)
+ REG_S x23, PT_S7(sp)
+ REG_S x24, PT_S8(sp)
+ REG_S x25, PT_S9(sp)
+ REG_S x26, PT_S10(sp)
+ REG_S x27, PT_S11(sp)
+ REG_S x28, PT_T3(sp)
+ REG_S x29, PT_T4(sp)
+ REG_S x30, PT_T5(sp)
+ REG_S x31, PT_T6(sp)
+
+ REG_L s0, TASK_TI_KERNEL_SP(tp)
+ csrr s1, CSR_STATUS
+ csrr s2, CSR_EPC
+ csrr s3, CSR_TVAL
+ csrr s4, CSR_CAUSE
+ csrr s5, CSR_SCRATCH
+ REG_S s0, PT_SP(sp)
+ REG_S s1, PT_STATUS(sp)
+ REG_S s2, PT_EPC(sp)
+ REG_S s3, PT_BADADDR(sp)
+ REG_S s4, PT_CAUSE(sp)
+ REG_S s5, PT_TP(sp)
+ move a0, sp
+ tail handle_bad_stack
+#endif
+
END(handle_exception)
ENTRY(ret_from_fork)
diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
index 1357abf79570..ff8033b9fdd6 100644
--- a/arch/riscv/kernel/traps.c
+++ b/arch/riscv/kernel/traps.c
@@ -200,3 +200,38 @@ int is_valid_bugaddr(unsigned long pc)
void trap_init(void)
{
}
+
+#ifdef CONFIG_VMAP_STACK
+DEFINE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack)
+ __aligned(16);
+/*
+ * shadow stack, handled_ kernel_ stack_ overflow(in kernel/entry.S) is used
+ * to get per-cpu overflow stack(get_overflow_stack).
+ */
+long shadow_stack[SHADOW_OVERFLOW_STACK_SIZE/sizeof(long)];
+asmlinkage unsigned long get_overflow_stack(void)
+{
+ return (unsigned long)this_cpu_ptr(overflow_stack) +
+ OVERFLOW_STACK_SIZE;
+}
+
+asmlinkage void handle_bad_stack(struct pt_regs *regs)
+{
+ unsigned long tsk_stk = (unsigned long)current->stack;
+ unsigned long ovf_stk = (unsigned long)this_cpu_ptr(overflow_stack);
+
+ console_verbose();
+
+ pr_emerg("Insufficient stack space to handle exception!\n");
+ pr_emerg("Task stack: [0x%016lx..0x%016lx]\n",
+ tsk_stk, tsk_stk + THREAD_SIZE);
+ pr_emerg("Overflow stack: [0x%016lx..0x%016lx]\n",
+ ovf_stk, ovf_stk + OVERFLOW_STACK_SIZE);
+
+ __show_regs(regs);
+ panic("Kernel stack overflow");
+
+ for (;;)
+ wait_for_interrupt();
+}
+#endif
--
2.18.0.huawei.25
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [RFC PATCH] riscv: add VMAP_STACK overflow detection
@ 2021-05-07 9:25 ` Tong Tiangen
0 siblings, 0 replies; 9+ messages in thread
From: Tong Tiangen @ 2021-05-07 9:25 UTC (permalink / raw)
To: Paul Walmsley, Palmer Dabbelt, Albert Ou
Cc: linux-riscv, linux-kernel, Tong Tiangen
This patch adds stack overflow detection to riscv, usable when
CONFIG_VMAP_STACK=y.
Overflow is detected in kernel exception entry(kernel/entry.S), if the kernel
stack is overflow and been detected, the overflow handler is invoked on a
per-cpu overflow stack. This approach preserves GPRs and the original exception
information.
The overflow detect is performed before any attempt is made to access the stack
and the principle of stack overflow detection: kernel stacks are aligned to
double their size, enabling overflow to be detected with a single bit test. For
example, a 16K stack is aligned to 32K, ensuring that bit 14 of the SP must be
zero. On an overflow (or underflow), this bit is flipped. Thus, overflow (of
less than the size of the stack) can be detected by testing whether this bit is
set.
This gives us a useful error message on stack overflow, as can be trigger with
the LKDTM overflow test:
[ 388.053267] lkdtm: Performing direct entry EXHAUST_STACK
[ 388.053663] lkdtm: Calling function with 1024 frame size to depth 32 ...
[ 388.054016] lkdtm: loop 32/32 ...
[ 388.054186] lkdtm: loop 31/32 ...
[ 388.054491] lkdtm: loop 30/32 ...
[ 388.054672] lkdtm: loop 29/32 ...
[ 388.054859] lkdtm: loop 28/32 ...
[ 388.055010] lkdtm: loop 27/32 ...
[ 388.055163] lkdtm: loop 26/32 ...
[ 388.055309] lkdtm: loop 25/32 ...
[ 388.055481] lkdtm: loop 24/32 ...
[ 388.055653] lkdtm: loop 23/32 ...
[ 388.055837] lkdtm: loop 22/32 ...
[ 388.056015] lkdtm: loop 21/32 ...
[ 388.056188] lkdtm: loop 20/32 ...
[ 388.058145] Insufficient stack space to handle exception!
[ 388.058153] Task stack: [0xffffffd014260000..0xffffffd014264000]
[ 388.058160] Overflow stack: [0xffffffe1f8d2c220..0xffffffe1f8d2d220]
[ 388.058168] CPU: 0 PID: 89 Comm: bash Not tainted 5.12.0-rc8-dirty #90
[ 388.058175] Hardware name: riscv-virtio,qemu (DT)
[ 388.058187] epc : number+0x32/0x2c0
[ 388.058247] ra : vsnprintf+0x2ae/0x3f0
[ 388.058255] epc : ffffffe0002d38f6 ra : ffffffe0002d814e sp : ffffffd01425ffc0
[ 388.058263] gp : ffffffe0012e4010 tp : ffffffe08014da00 t0 : ffffffd0142606e8
[ 388.058271] t1 : 0000000000000000 t2 : 0000000000000000 s0 : ffffffd014260070
[ 388.058303] s1 : ffffffd014260158 a0 : ffffffd01426015e a1 : ffffffd014260158
[ 388.058311] a2 : 0000000000000013 a3 : ffff0a01ffffff10 a4 : ffffffe000c398e0
[ 388.058319] a5 : 511b02ec65f3e300 a6 : 0000000000a1749a a7 : 0000000000000000
[ 388.058327] s2 : ffffffff000000ff s3 : 00000000ffff0a01 s4 : ffffffe0012e50a8
[ 388.058335] s5 : 0000000000ffff0a s6 : ffffffe0012e50a8 s7 : ffffffe000da1cc0
[ 388.058343] s8 : ffffffffffffffff s9 : ffffffd0142602b0 s10: ffffffd0142602a8
[ 388.058351] s11: ffffffd01426015e t3 : 00000000000f0000 t4 : ffffffffffffffff
[ 388.058359] t5 : 000000000000002f t6 : ffffffd014260158
[ 388.058366] status: 0000000000000100 badaddr: ffffffd01425fff8 cause: 000000000000000f
[ 388.058374] Kernel panic - not syncing: Kernel stack overflow
[ 388.058381] CPU: 0 PID: 89 Comm: bash Not tainted 5.12.0-rc8-dirty #90
[ 388.058387] Hardware name: riscv-virtio,qemu (DT)
[ 388.058393] Call Trace:
[ 388.058400] [<ffffffe000004944>] walk_stackframe+0x0/0xce
[ 388.058406] [<ffffffe0006f0b28>] dump_backtrace+0x38/0x46
[ 388.058412] [<ffffffe0006f0b46>] show_stack+0x10/0x18
[ 388.058418] [<ffffffe0006f3690>] dump_stack+0x74/0x8e
[ 388.058424] [<ffffffe0006f0d52>] panic+0xfc/0x2b2
[ 388.058430] [<ffffffe0006f0acc>] print_trace_address+0x0/0x24
[ 388.058436] [<ffffffe0002d814e>] vsnprintf+0x2ae/0x3f0
[ 388.058956] SMP: stopping secondary CPUs
Signed-off-by: Tong Tiangen <tongtiangen@huawei.com>
---
arch/riscv/Kconfig | 1 +
arch/riscv/include/asm/thread_info.h | 15 ++++
arch/riscv/kernel/entry.S | 108 +++++++++++++++++++++++++++
arch/riscv/kernel/traps.c | 35 +++++++++
4 files changed, 159 insertions(+)
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 4515a10c5d22..587f001e84f4 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -63,6 +63,7 @@ config RISCV
select HAVE_ARCH_MMAP_RND_BITS if MMU
select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_TRACEHOOK
+ select HAVE_ARCH_VMAP_STACK
select HAVE_ASM_MODVERSIONS
select HAVE_CONTEXT_TRACKING
select HAVE_DEBUG_KMEMLEAK
diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h
index 0e549a3089b3..60da0dcacf14 100644
--- a/arch/riscv/include/asm/thread_info.h
+++ b/arch/riscv/include/asm/thread_info.h
@@ -19,6 +19,21 @@
#endif
#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
+/*
+ * By aligning VMAP'd stacks to 2 * THREAD_SIZE, we can detect overflow by
+ * checking sp & (1 << THREAD_SHIFT), which we can do cheaply in the entry
+ * assembly.
+ */
+#ifdef CONFIG_VMAP_STACK
+#define THREAD_ALIGN (2 * THREAD_SIZE)
+#else
+#define THREAD_ALIGN THREAD_SIZE
+#endif
+
+#define THREAD_SHIFT (PAGE_SHIFT + THREAD_SIZE_ORDER)
+#define OVERFLOW_STACK_SIZE SZ_4K
+#define SHADOW_OVERFLOW_STACK_SIZE (1024)
+
#ifndef __ASSEMBLY__
#include <asm/processor.h>
diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
index 83095faa680e..deadf4000b86 100644
--- a/arch/riscv/kernel/entry.S
+++ b/arch/riscv/kernel/entry.S
@@ -29,6 +29,15 @@ ENTRY(handle_exception)
_restore_kernel_tpsp:
csrr tp, CSR_SCRATCH
REG_S sp, TASK_TI_KERNEL_SP(tp)
+
+#ifdef CONFIG_VMAP_STACK
+ addi sp, sp, -(PT_SIZE_ON_STACK)
+ srli sp, sp, THREAD_SHIFT
+ andi sp, sp, 0x1
+ bnez sp, handle_kernel_stack_overflow
+ REG_L sp, TASK_TI_KERNEL_SP(tp)
+#endif
+
_save_context:
REG_S sp, TASK_TI_USER_SP(tp)
REG_L sp, TASK_TI_KERNEL_SP(tp)
@@ -375,6 +384,105 @@ handle_syscall_trace_exit:
call do_syscall_trace_exit
j ret_from_exception
+#ifdef CONFIG_VMAP_STACK
+handle_kernel_stack_overflow:
+ la sp, shadow_stack
+ addi sp, sp, SHADOW_OVERFLOW_STACK_SIZE
+
+ //save caller register to shadow stack
+ addi sp, sp, -(PT_SIZE_ON_STACK)
+ REG_S x1, PT_RA(sp)
+ REG_S x5, PT_T0(sp)
+ REG_S x6, PT_T1(sp)
+ REG_S x7, PT_T2(sp)
+ REG_S x10, PT_A0(sp)
+ REG_S x11, PT_A1(sp)
+ REG_S x12, PT_A2(sp)
+ REG_S x13, PT_A3(sp)
+ REG_S x14, PT_A4(sp)
+ REG_S x15, PT_A5(sp)
+ REG_S x16, PT_A6(sp)
+ REG_S x17, PT_A7(sp)
+ REG_S x28, PT_T3(sp)
+ REG_S x29, PT_T4(sp)
+ REG_S x30, PT_T5(sp)
+ REG_S x31, PT_T6(sp)
+
+ la ra, restore_caller_reg
+ tail get_overflow_stack
+
+restore_caller_reg:
+ //save per-cpu overflow stack
+ sd a0, -8(sp)
+ //restore caller register from shadow_stack
+ REG_L x1, PT_RA(sp)
+ REG_L x5, PT_T0(sp)
+ REG_L x6, PT_T1(sp)
+ REG_L x7, PT_T2(sp)
+ REG_L x10, PT_A0(sp)
+ REG_L x11, PT_A1(sp)
+ REG_L x12, PT_A2(sp)
+ REG_L x13, PT_A3(sp)
+ REG_L x14, PT_A4(sp)
+ REG_L x15, PT_A5(sp)
+ REG_L x16, PT_A6(sp)
+ REG_L x17, PT_A7(sp)
+ REG_L x28, PT_T3(sp)
+ REG_L x29, PT_T4(sp)
+ REG_L x30, PT_T5(sp)
+ REG_L x31, PT_T6(sp)
+
+ //load per-cpu overflow stack
+ ld sp, -8(sp)
+ addi sp, sp, -(PT_SIZE_ON_STACK)
+
+ //save context to overflow stack
+ REG_S x1, PT_RA(sp)
+ REG_S x3, PT_GP(sp)
+ REG_S x5, PT_T0(sp)
+ REG_S x6, PT_T1(sp)
+ REG_S x7, PT_T2(sp)
+ REG_S x8, PT_S0(sp)
+ REG_S x9, PT_S1(sp)
+ REG_S x10, PT_A0(sp)
+ REG_S x11, PT_A1(sp)
+ REG_S x12, PT_A2(sp)
+ REG_S x13, PT_A3(sp)
+ REG_S x14, PT_A4(sp)
+ REG_S x15, PT_A5(sp)
+ REG_S x16, PT_A6(sp)
+ REG_S x17, PT_A7(sp)
+ REG_S x18, PT_S2(sp)
+ REG_S x19, PT_S3(sp)
+ REG_S x20, PT_S4(sp)
+ REG_S x21, PT_S5(sp)
+ REG_S x22, PT_S6(sp)
+ REG_S x23, PT_S7(sp)
+ REG_S x24, PT_S8(sp)
+ REG_S x25, PT_S9(sp)
+ REG_S x26, PT_S10(sp)
+ REG_S x27, PT_S11(sp)
+ REG_S x28, PT_T3(sp)
+ REG_S x29, PT_T4(sp)
+ REG_S x30, PT_T5(sp)
+ REG_S x31, PT_T6(sp)
+
+ REG_L s0, TASK_TI_KERNEL_SP(tp)
+ csrr s1, CSR_STATUS
+ csrr s2, CSR_EPC
+ csrr s3, CSR_TVAL
+ csrr s4, CSR_CAUSE
+ csrr s5, CSR_SCRATCH
+ REG_S s0, PT_SP(sp)
+ REG_S s1, PT_STATUS(sp)
+ REG_S s2, PT_EPC(sp)
+ REG_S s3, PT_BADADDR(sp)
+ REG_S s4, PT_CAUSE(sp)
+ REG_S s5, PT_TP(sp)
+ move a0, sp
+ tail handle_bad_stack
+#endif
+
END(handle_exception)
ENTRY(ret_from_fork)
diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
index 1357abf79570..ff8033b9fdd6 100644
--- a/arch/riscv/kernel/traps.c
+++ b/arch/riscv/kernel/traps.c
@@ -200,3 +200,38 @@ int is_valid_bugaddr(unsigned long pc)
void trap_init(void)
{
}
+
+#ifdef CONFIG_VMAP_STACK
+DEFINE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack)
+ __aligned(16);
+/*
+ * shadow stack, handled_ kernel_ stack_ overflow(in kernel/entry.S) is used
+ * to get per-cpu overflow stack(get_overflow_stack).
+ */
+long shadow_stack[SHADOW_OVERFLOW_STACK_SIZE/sizeof(long)];
+asmlinkage unsigned long get_overflow_stack(void)
+{
+ return (unsigned long)this_cpu_ptr(overflow_stack) +
+ OVERFLOW_STACK_SIZE;
+}
+
+asmlinkage void handle_bad_stack(struct pt_regs *regs)
+{
+ unsigned long tsk_stk = (unsigned long)current->stack;
+ unsigned long ovf_stk = (unsigned long)this_cpu_ptr(overflow_stack);
+
+ console_verbose();
+
+ pr_emerg("Insufficient stack space to handle exception!\n");
+ pr_emerg("Task stack: [0x%016lx..0x%016lx]\n",
+ tsk_stk, tsk_stk + THREAD_SIZE);
+ pr_emerg("Overflow stack: [0x%016lx..0x%016lx]\n",
+ ovf_stk, ovf_stk + OVERFLOW_STACK_SIZE);
+
+ __show_regs(regs);
+ panic("Kernel stack overflow");
+
+ for (;;)
+ wait_for_interrupt();
+}
+#endif
--
2.18.0.huawei.25
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [RFC PATCH] riscv: add VMAP_STACK overflow detection
2021-05-07 9:25 ` Tong Tiangen
(?)
@ 2021-05-07 12:00 ` kernel test robot
-1 siblings, 0 replies; 9+ messages in thread
From: kernel test robot @ 2021-05-07 12:00 UTC (permalink / raw)
To: kbuild-all
[-- Attachment #1: Type: text/plain, Size: 3370 bytes --]
Hi Tong,
[FYI, it's a private test report for your RFC patch.]
[auto build test WARNING on v5.12]
[also build test WARNING on next-20210507]
[cannot apply to linus/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Tong-Tiangen/riscv-add-VMAP_STACK-overflow-detection/20210507-171736
base: 9f4ad9e425a1d3b6a34617b8ea226d56a119a717
config: riscv-randconfig-r015-20210507 (attached as .config)
compiler: clang version 13.0.0 (https://github.com/llvm/llvm-project a3a8a1a15b524d91b5308db68e9d293b34cd88dd)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install riscv cross compiling tool for clang build
# apt-get install binutils-riscv64-linux-gnu
# https://github.com/0day-ci/linux/commit/60d8a3da002bf59ec0abeb88403dbb11cf31583f
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Tong-Tiangen/riscv-add-VMAP_STACK-overflow-detection/20210507-171736
git checkout 60d8a3da002bf59ec0abeb88403dbb11cf31583f
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 ARCH=riscv
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All warnings (new ones prefixed by >>):
>> arch/riscv/kernel/traps.c:212:26: warning: no previous prototype for function 'get_overflow_stack' [-Wmissing-prototypes]
asmlinkage unsigned long get_overflow_stack(void)
^
arch/riscv/kernel/traps.c:212:12: note: declare 'static' if the function is not intended to be used outside of this translation unit
asmlinkage unsigned long get_overflow_stack(void)
^
static
>> arch/riscv/kernel/traps.c:218:17: warning: no previous prototype for function 'handle_bad_stack' [-Wmissing-prototypes]
asmlinkage void handle_bad_stack(struct pt_regs *regs)
^
arch/riscv/kernel/traps.c:218:12: note: declare 'static' if the function is not intended to be used outside of this translation unit
asmlinkage void handle_bad_stack(struct pt_regs *regs)
^
static
2 warnings generated.
vim +/get_overflow_stack +212 arch/riscv/kernel/traps.c
203
204 #ifdef CONFIG_VMAP_STACK
205 DEFINE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack)
206 __aligned(16);
207 /*
208 * shadow stack, handled_ kernel_ stack_ overflow(in kernel/entry.S) is used
209 * to get per-cpu overflow stack(get_overflow_stack).
210 */
211 long shadow_stack[SHADOW_OVERFLOW_STACK_SIZE/sizeof(long)];
> 212 asmlinkage unsigned long get_overflow_stack(void)
213 {
214 return (unsigned long)this_cpu_ptr(overflow_stack) +
215 OVERFLOW_STACK_SIZE;
216 }
217
> 218 asmlinkage void handle_bad_stack(struct pt_regs *regs)
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 31413 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH] riscv: add VMAP_STACK overflow detection
2021-05-07 9:25 ` Tong Tiangen
(?)
(?)
@ 2021-05-07 12:37 ` kernel test robot
-1 siblings, 0 replies; 9+ messages in thread
From: kernel test robot @ 2021-05-07 12:37 UTC (permalink / raw)
To: kbuild-all
[-- Attachment #1: Type: text/plain, Size: 1811 bytes --]
Hi Tong,
[FYI, it's a private test report for your RFC patch.]
[auto build test ERROR on v5.12]
[also build test ERROR on next-20210507]
[cannot apply to linus/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Tong-Tiangen/riscv-add-VMAP_STACK-overflow-detection/20210507-171736
base: 9f4ad9e425a1d3b6a34617b8ea226d56a119a717
config: riscv-nommu_k210_defconfig (attached as .config)
compiler: riscv64-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/60d8a3da002bf59ec0abeb88403dbb11cf31583f
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Tong-Tiangen/riscv-add-VMAP_STACK-overflow-detection/20210507-171736
git checkout 60d8a3da002bf59ec0abeb88403dbb11cf31583f
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross W=1 ARCH=riscv
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All errors (new ones prefixed by >>):
riscv64-linux-ld: kernel/fork.o: in function `.L59':
>> fork.c:(.text+0x222): undefined reference to `vfree_atomic'
riscv64-linux-ld: kernel/fork.o: in function `.L283':
>> fork.c:(.text+0xd8a): undefined reference to `find_vm_area'
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 8401 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH] riscv: add VMAP_STACK overflow detection
2021-05-07 9:25 ` Tong Tiangen
` (2 preceding siblings ...)
(?)
@ 2021-05-07 13:22 ` kernel test robot
-1 siblings, 0 replies; 9+ messages in thread
From: kernel test robot @ 2021-05-07 13:22 UTC (permalink / raw)
To: kbuild-all
[-- Attachment #1: Type: text/plain, Size: 5861 bytes --]
Hi Tong,
[FYI, it's a private test report for your RFC patch.]
[auto build test ERROR on v5.12]
[also build test ERROR on next-20210507]
[cannot apply to linus/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Tong-Tiangen/riscv-add-VMAP_STACK-overflow-detection/20210507-171736
base: 9f4ad9e425a1d3b6a34617b8ea226d56a119a717
config: riscv-rv32_defconfig (attached as .config)
compiler: riscv32-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/60d8a3da002bf59ec0abeb88403dbb11cf31583f
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Tong-Tiangen/riscv-add-VMAP_STACK-overflow-detection/20210507-171736
git checkout 60d8a3da002bf59ec0abeb88403dbb11cf31583f
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross W=1 ARCH=riscv
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All errors (new ones prefixed by >>):
arch/riscv/kernel/entry.S: Assembler messages:
>> arch/riscv/kernel/entry.S:416: Error: unrecognized opcode `sd a0,-8(sp)'
>> arch/riscv/kernel/entry.S:436: Error: unrecognized opcode `ld sp,-8(sp)'
vim +416 arch/riscv/kernel/entry.S
352
353 work_pending:
354 /* Enter slow path for supplementary processing */
355 la ra, ret_from_exception
356 andi s1, s0, _TIF_NEED_RESCHED
357 bnez s1, work_resched
358 work_notifysig:
359 /* Handle pending signals and notify-resume requests */
360 csrs CSR_STATUS, SR_IE /* Enable interrupts for do_notify_resume() */
361 move a0, sp /* pt_regs */
362 move a1, s0 /* current_thread_info->flags */
363 tail do_notify_resume
364 work_resched:
365 tail schedule
366
367 /* Slow paths for ptrace. */
368 handle_syscall_trace_enter:
369 move a0, sp
370 call do_syscall_trace_enter
371 move t0, a0
372 REG_L a0, PT_A0(sp)
373 REG_L a1, PT_A1(sp)
374 REG_L a2, PT_A2(sp)
375 REG_L a3, PT_A3(sp)
376 REG_L a4, PT_A4(sp)
377 REG_L a5, PT_A5(sp)
378 REG_L a6, PT_A6(sp)
379 REG_L a7, PT_A7(sp)
380 bnez t0, ret_from_syscall_rejected
381 j check_syscall_nr
382 handle_syscall_trace_exit:
383 move a0, sp
384 call do_syscall_trace_exit
385 j ret_from_exception
386
387 #ifdef CONFIG_VMAP_STACK
388 handle_kernel_stack_overflow:
389 la sp, shadow_stack
390 addi sp, sp, SHADOW_OVERFLOW_STACK_SIZE
391
392 //save caller register to shadow stack
393 addi sp, sp, -(PT_SIZE_ON_STACK)
394 REG_S x1, PT_RA(sp)
395 REG_S x5, PT_T0(sp)
396 REG_S x6, PT_T1(sp)
397 REG_S x7, PT_T2(sp)
398 REG_S x10, PT_A0(sp)
399 REG_S x11, PT_A1(sp)
400 REG_S x12, PT_A2(sp)
401 REG_S x13, PT_A3(sp)
402 REG_S x14, PT_A4(sp)
403 REG_S x15, PT_A5(sp)
404 REG_S x16, PT_A6(sp)
405 REG_S x17, PT_A7(sp)
406 REG_S x28, PT_T3(sp)
407 REG_S x29, PT_T4(sp)
408 REG_S x30, PT_T5(sp)
409 REG_S x31, PT_T6(sp)
410
411 la ra, restore_caller_reg
412 tail get_overflow_stack
413
414 restore_caller_reg:
415 //save per-cpu overflow stack
> 416 sd a0, -8(sp)
417 //restore caller register from shadow_stack
418 REG_L x1, PT_RA(sp)
419 REG_L x5, PT_T0(sp)
420 REG_L x6, PT_T1(sp)
421 REG_L x7, PT_T2(sp)
422 REG_L x10, PT_A0(sp)
423 REG_L x11, PT_A1(sp)
424 REG_L x12, PT_A2(sp)
425 REG_L x13, PT_A3(sp)
426 REG_L x14, PT_A4(sp)
427 REG_L x15, PT_A5(sp)
428 REG_L x16, PT_A6(sp)
429 REG_L x17, PT_A7(sp)
430 REG_L x28, PT_T3(sp)
431 REG_L x29, PT_T4(sp)
432 REG_L x30, PT_T5(sp)
433 REG_L x31, PT_T6(sp)
434
435 //load per-cpu overflow stack
> 436 ld sp, -8(sp)
437 addi sp, sp, -(PT_SIZE_ON_STACK)
438
439 //save context to overflow stack
440 REG_S x1, PT_RA(sp)
441 REG_S x3, PT_GP(sp)
442 REG_S x5, PT_T0(sp)
443 REG_S x6, PT_T1(sp)
444 REG_S x7, PT_T2(sp)
445 REG_S x8, PT_S0(sp)
446 REG_S x9, PT_S1(sp)
447 REG_S x10, PT_A0(sp)
448 REG_S x11, PT_A1(sp)
449 REG_S x12, PT_A2(sp)
450 REG_S x13, PT_A3(sp)
451 REG_S x14, PT_A4(sp)
452 REG_S x15, PT_A5(sp)
453 REG_S x16, PT_A6(sp)
454 REG_S x17, PT_A7(sp)
455 REG_S x18, PT_S2(sp)
456 REG_S x19, PT_S3(sp)
457 REG_S x20, PT_S4(sp)
458 REG_S x21, PT_S5(sp)
459 REG_S x22, PT_S6(sp)
460 REG_S x23, PT_S7(sp)
461 REG_S x24, PT_S8(sp)
462 REG_S x25, PT_S9(sp)
463 REG_S x26, PT_S10(sp)
464 REG_S x27, PT_S11(sp)
465 REG_S x28, PT_T3(sp)
466 REG_S x29, PT_T4(sp)
467 REG_S x30, PT_T5(sp)
468 REG_S x31, PT_T6(sp)
469
470 REG_L s0, TASK_TI_KERNEL_SP(tp)
471 csrr s1, CSR_STATUS
472 csrr s2, CSR_EPC
473 csrr s3, CSR_TVAL
474 csrr s4, CSR_CAUSE
475 csrr s5, CSR_SCRATCH
476 REG_S s0, PT_SP(sp)
477 REG_S s1, PT_STATUS(sp)
478 REG_S s2, PT_EPC(sp)
479 REG_S s3, PT_BADADDR(sp)
480 REG_S s4, PT_CAUSE(sp)
481 REG_S s5, PT_TP(sp)
482 move a0, sp
483 tail handle_bad_stack
484 #endif
485
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 20565 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH] riscv: add VMAP_STACK overflow detection
2021-05-07 9:25 ` Tong Tiangen
@ 2021-05-23 1:49 ` Palmer Dabbelt
-1 siblings, 0 replies; 9+ messages in thread
From: Palmer Dabbelt @ 2021-05-23 1:49 UTC (permalink / raw)
To: tongtiangen; +Cc: Paul Walmsley, aou, linux-riscv, linux-kernel, tongtiangen
On Fri, 07 May 2021 02:25:09 PDT (-0700), tongtiangen@huawei.com wrote:
> This patch adds stack overflow detection to riscv, usable when
> CONFIG_VMAP_STACK=y.
>
> Overflow is detected in kernel exception entry(kernel/entry.S), if the kernel
> stack is overflow and been detected, the overflow handler is invoked on a
> per-cpu overflow stack. This approach preserves GPRs and the original exception
> information.
>
> The overflow detect is performed before any attempt is made to access the stack
> and the principle of stack overflow detection: kernel stacks are aligned to
> double their size, enabling overflow to be detected with a single bit test. For
> example, a 16K stack is aligned to 32K, ensuring that bit 14 of the SP must be
> zero. On an overflow (or underflow), this bit is flipped. Thus, overflow (of
> less than the size of the stack) can be detected by testing whether this bit is
> set.
>
> This gives us a useful error message on stack overflow, as can be trigger with
> the LKDTM overflow test:
>
> [ 388.053267] lkdtm: Performing direct entry EXHAUST_STACK
> [ 388.053663] lkdtm: Calling function with 1024 frame size to depth 32 ...
> [ 388.054016] lkdtm: loop 32/32 ...
> [ 388.054186] lkdtm: loop 31/32 ...
> [ 388.054491] lkdtm: loop 30/32 ...
> [ 388.054672] lkdtm: loop 29/32 ...
> [ 388.054859] lkdtm: loop 28/32 ...
> [ 388.055010] lkdtm: loop 27/32 ...
> [ 388.055163] lkdtm: loop 26/32 ...
> [ 388.055309] lkdtm: loop 25/32 ...
> [ 388.055481] lkdtm: loop 24/32 ...
> [ 388.055653] lkdtm: loop 23/32 ...
> [ 388.055837] lkdtm: loop 22/32 ...
> [ 388.056015] lkdtm: loop 21/32 ...
> [ 388.056188] lkdtm: loop 20/32 ...
> [ 388.058145] Insufficient stack space to handle exception!
> [ 388.058153] Task stack: [0xffffffd014260000..0xffffffd014264000]
> [ 388.058160] Overflow stack: [0xffffffe1f8d2c220..0xffffffe1f8d2d220]
> [ 388.058168] CPU: 0 PID: 89 Comm: bash Not tainted 5.12.0-rc8-dirty #90
> [ 388.058175] Hardware name: riscv-virtio,qemu (DT)
> [ 388.058187] epc : number+0x32/0x2c0
> [ 388.058247] ra : vsnprintf+0x2ae/0x3f0
> [ 388.058255] epc : ffffffe0002d38f6 ra : ffffffe0002d814e sp : ffffffd01425ffc0
> [ 388.058263] gp : ffffffe0012e4010 tp : ffffffe08014da00 t0 : ffffffd0142606e8
> [ 388.058271] t1 : 0000000000000000 t2 : 0000000000000000 s0 : ffffffd014260070
> [ 388.058303] s1 : ffffffd014260158 a0 : ffffffd01426015e a1 : ffffffd014260158
> [ 388.058311] a2 : 0000000000000013 a3 : ffff0a01ffffff10 a4 : ffffffe000c398e0
> [ 388.058319] a5 : 511b02ec65f3e300 a6 : 0000000000a1749a a7 : 0000000000000000
> [ 388.058327] s2 : ffffffff000000ff s3 : 00000000ffff0a01 s4 : ffffffe0012e50a8
> [ 388.058335] s5 : 0000000000ffff0a s6 : ffffffe0012e50a8 s7 : ffffffe000da1cc0
> [ 388.058343] s8 : ffffffffffffffff s9 : ffffffd0142602b0 s10: ffffffd0142602a8
> [ 388.058351] s11: ffffffd01426015e t3 : 00000000000f0000 t4 : ffffffffffffffff
> [ 388.058359] t5 : 000000000000002f t6 : ffffffd014260158
> [ 388.058366] status: 0000000000000100 badaddr: ffffffd01425fff8 cause: 000000000000000f
> [ 388.058374] Kernel panic - not syncing: Kernel stack overflow
> [ 388.058381] CPU: 0 PID: 89 Comm: bash Not tainted 5.12.0-rc8-dirty #90
> [ 388.058387] Hardware name: riscv-virtio,qemu (DT)
> [ 388.058393] Call Trace:
> [ 388.058400] [<ffffffe000004944>] walk_stackframe+0x0/0xce
> [ 388.058406] [<ffffffe0006f0b28>] dump_backtrace+0x38/0x46
> [ 388.058412] [<ffffffe0006f0b46>] show_stack+0x10/0x18
> [ 388.058418] [<ffffffe0006f3690>] dump_stack+0x74/0x8e
> [ 388.058424] [<ffffffe0006f0d52>] panic+0xfc/0x2b2
> [ 388.058430] [<ffffffe0006f0acc>] print_trace_address+0x0/0x24
> [ 388.058436] [<ffffffe0002d814e>] vsnprintf+0x2ae/0x3f0
> [ 388.058956] SMP: stopping secondary CPUs
>
> Signed-off-by: Tong Tiangen <tongtiangen@huawei.com>
> ---
> arch/riscv/Kconfig | 1 +
> arch/riscv/include/asm/thread_info.h | 15 ++++
> arch/riscv/kernel/entry.S | 108 +++++++++++++++++++++++++++
> arch/riscv/kernel/traps.c | 35 +++++++++
> 4 files changed, 159 insertions(+)
>
> diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
> index 4515a10c5d22..587f001e84f4 100644
> --- a/arch/riscv/Kconfig
> +++ b/arch/riscv/Kconfig
> @@ -63,6 +63,7 @@ config RISCV
> select HAVE_ARCH_MMAP_RND_BITS if MMU
> select HAVE_ARCH_SECCOMP_FILTER
> select HAVE_ARCH_TRACEHOOK
> + select HAVE_ARCH_VMAP_STACK
> select HAVE_ASM_MODVERSIONS
> select HAVE_CONTEXT_TRACKING
> select HAVE_DEBUG_KMEMLEAK
> diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h
> index 0e549a3089b3..60da0dcacf14 100644
> --- a/arch/riscv/include/asm/thread_info.h
> +++ b/arch/riscv/include/asm/thread_info.h
> @@ -19,6 +19,21 @@
> #endif
> #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
>
> +/*
> + * By aligning VMAP'd stacks to 2 * THREAD_SIZE, we can detect overflow by
> + * checking sp & (1 << THREAD_SHIFT), which we can do cheaply in the entry
> + * assembly.
> + */
> +#ifdef CONFIG_VMAP_STACK
> +#define THREAD_ALIGN (2 * THREAD_SIZE)
> +#else
> +#define THREAD_ALIGN THREAD_SIZE
> +#endif
> +
> +#define THREAD_SHIFT (PAGE_SHIFT + THREAD_SIZE_ORDER)
> +#define OVERFLOW_STACK_SIZE SZ_4K
> +#define SHADOW_OVERFLOW_STACK_SIZE (1024)
> +
> #ifndef __ASSEMBLY__
>
> #include <asm/processor.h>
> diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
> index 83095faa680e..deadf4000b86 100644
> --- a/arch/riscv/kernel/entry.S
> +++ b/arch/riscv/kernel/entry.S
> @@ -29,6 +29,15 @@ ENTRY(handle_exception)
> _restore_kernel_tpsp:
> csrr tp, CSR_SCRATCH
> REG_S sp, TASK_TI_KERNEL_SP(tp)
> +
> +#ifdef CONFIG_VMAP_STACK
> + addi sp, sp, -(PT_SIZE_ON_STACK)
> + srli sp, sp, THREAD_SHIFT
> + andi sp, sp, 0x1
> + bnez sp, handle_kernel_stack_overflow
> + REG_L sp, TASK_TI_KERNEL_SP(tp)
> +#endif
> +
> _save_context:
> REG_S sp, TASK_TI_USER_SP(tp)
> REG_L sp, TASK_TI_KERNEL_SP(tp)
> @@ -375,6 +384,105 @@ handle_syscall_trace_exit:
> call do_syscall_trace_exit
> j ret_from_exception
>
> +#ifdef CONFIG_VMAP_STACK
> +handle_kernel_stack_overflow:
> + la sp, shadow_stack
> + addi sp, sp, SHADOW_OVERFLOW_STACK_SIZE
> +
> + //save caller register to shadow stack
> + addi sp, sp, -(PT_SIZE_ON_STACK)
> + REG_S x1, PT_RA(sp)
> + REG_S x5, PT_T0(sp)
> + REG_S x6, PT_T1(sp)
> + REG_S x7, PT_T2(sp)
> + REG_S x10, PT_A0(sp)
> + REG_S x11, PT_A1(sp)
> + REG_S x12, PT_A2(sp)
> + REG_S x13, PT_A3(sp)
> + REG_S x14, PT_A4(sp)
> + REG_S x15, PT_A5(sp)
> + REG_S x16, PT_A6(sp)
> + REG_S x17, PT_A7(sp)
> + REG_S x28, PT_T3(sp)
> + REG_S x29, PT_T4(sp)
> + REG_S x30, PT_T5(sp)
> + REG_S x31, PT_T6(sp)
> +
> + la ra, restore_caller_reg
> + tail get_overflow_stack
> +
> +restore_caller_reg:
> + //save per-cpu overflow stack
> + sd a0, -8(sp)
> + //restore caller register from shadow_stack
> + REG_L x1, PT_RA(sp)
> + REG_L x5, PT_T0(sp)
> + REG_L x6, PT_T1(sp)
> + REG_L x7, PT_T2(sp)
> + REG_L x10, PT_A0(sp)
> + REG_L x11, PT_A1(sp)
> + REG_L x12, PT_A2(sp)
> + REG_L x13, PT_A3(sp)
> + REG_L x14, PT_A4(sp)
> + REG_L x15, PT_A5(sp)
> + REG_L x16, PT_A6(sp)
> + REG_L x17, PT_A7(sp)
> + REG_L x28, PT_T3(sp)
> + REG_L x29, PT_T4(sp)
> + REG_L x30, PT_T5(sp)
> + REG_L x31, PT_T6(sp)
> +
> + //load per-cpu overflow stack
> + ld sp, -8(sp)
> + addi sp, sp, -(PT_SIZE_ON_STACK)
> +
> + //save context to overflow stack
> + REG_S x1, PT_RA(sp)
> + REG_S x3, PT_GP(sp)
> + REG_S x5, PT_T0(sp)
> + REG_S x6, PT_T1(sp)
> + REG_S x7, PT_T2(sp)
> + REG_S x8, PT_S0(sp)
> + REG_S x9, PT_S1(sp)
> + REG_S x10, PT_A0(sp)
> + REG_S x11, PT_A1(sp)
> + REG_S x12, PT_A2(sp)
> + REG_S x13, PT_A3(sp)
> + REG_S x14, PT_A4(sp)
> + REG_S x15, PT_A5(sp)
> + REG_S x16, PT_A6(sp)
> + REG_S x17, PT_A7(sp)
> + REG_S x18, PT_S2(sp)
> + REG_S x19, PT_S3(sp)
> + REG_S x20, PT_S4(sp)
> + REG_S x21, PT_S5(sp)
> + REG_S x22, PT_S6(sp)
> + REG_S x23, PT_S7(sp)
> + REG_S x24, PT_S8(sp)
> + REG_S x25, PT_S9(sp)
> + REG_S x26, PT_S10(sp)
> + REG_S x27, PT_S11(sp)
> + REG_S x28, PT_T3(sp)
> + REG_S x29, PT_T4(sp)
> + REG_S x30, PT_T5(sp)
> + REG_S x31, PT_T6(sp)
> +
> + REG_L s0, TASK_TI_KERNEL_SP(tp)
> + csrr s1, CSR_STATUS
> + csrr s2, CSR_EPC
> + csrr s3, CSR_TVAL
> + csrr s4, CSR_CAUSE
> + csrr s5, CSR_SCRATCH
> + REG_S s0, PT_SP(sp)
> + REG_S s1, PT_STATUS(sp)
> + REG_S s2, PT_EPC(sp)
> + REG_S s3, PT_BADADDR(sp)
> + REG_S s4, PT_CAUSE(sp)
> + REG_S s5, PT_TP(sp)
> + move a0, sp
> + tail handle_bad_stack
> +#endif
> +
> END(handle_exception)
>
> ENTRY(ret_from_fork)
> diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
> index 1357abf79570..ff8033b9fdd6 100644
> --- a/arch/riscv/kernel/traps.c
> +++ b/arch/riscv/kernel/traps.c
> @@ -200,3 +200,38 @@ int is_valid_bugaddr(unsigned long pc)
> void trap_init(void)
> {
> }
> +
> +#ifdef CONFIG_VMAP_STACK
> +DEFINE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack)
> + __aligned(16);
> +/*
> + * shadow stack, handled_ kernel_ stack_ overflow(in kernel/entry.S) is used
> + * to get per-cpu overflow stack(get_overflow_stack).
> + */
> +long shadow_stack[SHADOW_OVERFLOW_STACK_SIZE/sizeof(long)];
> +asmlinkage unsigned long get_overflow_stack(void)
> +{
> + return (unsigned long)this_cpu_ptr(overflow_stack) +
> + OVERFLOW_STACK_SIZE;
> +}
> +
> +asmlinkage void handle_bad_stack(struct pt_regs *regs)
> +{
> + unsigned long tsk_stk = (unsigned long)current->stack;
> + unsigned long ovf_stk = (unsigned long)this_cpu_ptr(overflow_stack);
> +
> + console_verbose();
> +
> + pr_emerg("Insufficient stack space to handle exception!\n");
> + pr_emerg("Task stack: [0x%016lx..0x%016lx]\n",
> + tsk_stk, tsk_stk + THREAD_SIZE);
> + pr_emerg("Overflow stack: [0x%016lx..0x%016lx]\n",
> + ovf_stk, ovf_stk + OVERFLOW_STACK_SIZE);
> +
> + __show_regs(regs);
> + panic("Kernel stack overflow");
> +
> + for (;;)
> + wait_for_interrupt();
> +}
> +#endif
This LGTM. It seems good enough to take, I'm not sure why this is an
RFC?
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH] riscv: add VMAP_STACK overflow detection
@ 2021-05-23 1:49 ` Palmer Dabbelt
0 siblings, 0 replies; 9+ messages in thread
From: Palmer Dabbelt @ 2021-05-23 1:49 UTC (permalink / raw)
To: tongtiangen; +Cc: Paul Walmsley, aou, linux-riscv, linux-kernel, tongtiangen
On Fri, 07 May 2021 02:25:09 PDT (-0700), tongtiangen@huawei.com wrote:
> This patch adds stack overflow detection to riscv, usable when
> CONFIG_VMAP_STACK=y.
>
> Overflow is detected in kernel exception entry(kernel/entry.S), if the kernel
> stack is overflow and been detected, the overflow handler is invoked on a
> per-cpu overflow stack. This approach preserves GPRs and the original exception
> information.
>
> The overflow detect is performed before any attempt is made to access the stack
> and the principle of stack overflow detection: kernel stacks are aligned to
> double their size, enabling overflow to be detected with a single bit test. For
> example, a 16K stack is aligned to 32K, ensuring that bit 14 of the SP must be
> zero. On an overflow (or underflow), this bit is flipped. Thus, overflow (of
> less than the size of the stack) can be detected by testing whether this bit is
> set.
>
> This gives us a useful error message on stack overflow, as can be trigger with
> the LKDTM overflow test:
>
> [ 388.053267] lkdtm: Performing direct entry EXHAUST_STACK
> [ 388.053663] lkdtm: Calling function with 1024 frame size to depth 32 ...
> [ 388.054016] lkdtm: loop 32/32 ...
> [ 388.054186] lkdtm: loop 31/32 ...
> [ 388.054491] lkdtm: loop 30/32 ...
> [ 388.054672] lkdtm: loop 29/32 ...
> [ 388.054859] lkdtm: loop 28/32 ...
> [ 388.055010] lkdtm: loop 27/32 ...
> [ 388.055163] lkdtm: loop 26/32 ...
> [ 388.055309] lkdtm: loop 25/32 ...
> [ 388.055481] lkdtm: loop 24/32 ...
> [ 388.055653] lkdtm: loop 23/32 ...
> [ 388.055837] lkdtm: loop 22/32 ...
> [ 388.056015] lkdtm: loop 21/32 ...
> [ 388.056188] lkdtm: loop 20/32 ...
> [ 388.058145] Insufficient stack space to handle exception!
> [ 388.058153] Task stack: [0xffffffd014260000..0xffffffd014264000]
> [ 388.058160] Overflow stack: [0xffffffe1f8d2c220..0xffffffe1f8d2d220]
> [ 388.058168] CPU: 0 PID: 89 Comm: bash Not tainted 5.12.0-rc8-dirty #90
> [ 388.058175] Hardware name: riscv-virtio,qemu (DT)
> [ 388.058187] epc : number+0x32/0x2c0
> [ 388.058247] ra : vsnprintf+0x2ae/0x3f0
> [ 388.058255] epc : ffffffe0002d38f6 ra : ffffffe0002d814e sp : ffffffd01425ffc0
> [ 388.058263] gp : ffffffe0012e4010 tp : ffffffe08014da00 t0 : ffffffd0142606e8
> [ 388.058271] t1 : 0000000000000000 t2 : 0000000000000000 s0 : ffffffd014260070
> [ 388.058303] s1 : ffffffd014260158 a0 : ffffffd01426015e a1 : ffffffd014260158
> [ 388.058311] a2 : 0000000000000013 a3 : ffff0a01ffffff10 a4 : ffffffe000c398e0
> [ 388.058319] a5 : 511b02ec65f3e300 a6 : 0000000000a1749a a7 : 0000000000000000
> [ 388.058327] s2 : ffffffff000000ff s3 : 00000000ffff0a01 s4 : ffffffe0012e50a8
> [ 388.058335] s5 : 0000000000ffff0a s6 : ffffffe0012e50a8 s7 : ffffffe000da1cc0
> [ 388.058343] s8 : ffffffffffffffff s9 : ffffffd0142602b0 s10: ffffffd0142602a8
> [ 388.058351] s11: ffffffd01426015e t3 : 00000000000f0000 t4 : ffffffffffffffff
> [ 388.058359] t5 : 000000000000002f t6 : ffffffd014260158
> [ 388.058366] status: 0000000000000100 badaddr: ffffffd01425fff8 cause: 000000000000000f
> [ 388.058374] Kernel panic - not syncing: Kernel stack overflow
> [ 388.058381] CPU: 0 PID: 89 Comm: bash Not tainted 5.12.0-rc8-dirty #90
> [ 388.058387] Hardware name: riscv-virtio,qemu (DT)
> [ 388.058393] Call Trace:
> [ 388.058400] [<ffffffe000004944>] walk_stackframe+0x0/0xce
> [ 388.058406] [<ffffffe0006f0b28>] dump_backtrace+0x38/0x46
> [ 388.058412] [<ffffffe0006f0b46>] show_stack+0x10/0x18
> [ 388.058418] [<ffffffe0006f3690>] dump_stack+0x74/0x8e
> [ 388.058424] [<ffffffe0006f0d52>] panic+0xfc/0x2b2
> [ 388.058430] [<ffffffe0006f0acc>] print_trace_address+0x0/0x24
> [ 388.058436] [<ffffffe0002d814e>] vsnprintf+0x2ae/0x3f0
> [ 388.058956] SMP: stopping secondary CPUs
>
> Signed-off-by: Tong Tiangen <tongtiangen@huawei.com>
> ---
> arch/riscv/Kconfig | 1 +
> arch/riscv/include/asm/thread_info.h | 15 ++++
> arch/riscv/kernel/entry.S | 108 +++++++++++++++++++++++++++
> arch/riscv/kernel/traps.c | 35 +++++++++
> 4 files changed, 159 insertions(+)
>
> diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
> index 4515a10c5d22..587f001e84f4 100644
> --- a/arch/riscv/Kconfig
> +++ b/arch/riscv/Kconfig
> @@ -63,6 +63,7 @@ config RISCV
> select HAVE_ARCH_MMAP_RND_BITS if MMU
> select HAVE_ARCH_SECCOMP_FILTER
> select HAVE_ARCH_TRACEHOOK
> + select HAVE_ARCH_VMAP_STACK
> select HAVE_ASM_MODVERSIONS
> select HAVE_CONTEXT_TRACKING
> select HAVE_DEBUG_KMEMLEAK
> diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h
> index 0e549a3089b3..60da0dcacf14 100644
> --- a/arch/riscv/include/asm/thread_info.h
> +++ b/arch/riscv/include/asm/thread_info.h
> @@ -19,6 +19,21 @@
> #endif
> #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
>
> +/*
> + * By aligning VMAP'd stacks to 2 * THREAD_SIZE, we can detect overflow by
> + * checking sp & (1 << THREAD_SHIFT), which we can do cheaply in the entry
> + * assembly.
> + */
> +#ifdef CONFIG_VMAP_STACK
> +#define THREAD_ALIGN (2 * THREAD_SIZE)
> +#else
> +#define THREAD_ALIGN THREAD_SIZE
> +#endif
> +
> +#define THREAD_SHIFT (PAGE_SHIFT + THREAD_SIZE_ORDER)
> +#define OVERFLOW_STACK_SIZE SZ_4K
> +#define SHADOW_OVERFLOW_STACK_SIZE (1024)
> +
> #ifndef __ASSEMBLY__
>
> #include <asm/processor.h>
> diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
> index 83095faa680e..deadf4000b86 100644
> --- a/arch/riscv/kernel/entry.S
> +++ b/arch/riscv/kernel/entry.S
> @@ -29,6 +29,15 @@ ENTRY(handle_exception)
> _restore_kernel_tpsp:
> csrr tp, CSR_SCRATCH
> REG_S sp, TASK_TI_KERNEL_SP(tp)
> +
> +#ifdef CONFIG_VMAP_STACK
> + addi sp, sp, -(PT_SIZE_ON_STACK)
> + srli sp, sp, THREAD_SHIFT
> + andi sp, sp, 0x1
> + bnez sp, handle_kernel_stack_overflow
> + REG_L sp, TASK_TI_KERNEL_SP(tp)
> +#endif
> +
> _save_context:
> REG_S sp, TASK_TI_USER_SP(tp)
> REG_L sp, TASK_TI_KERNEL_SP(tp)
> @@ -375,6 +384,105 @@ handle_syscall_trace_exit:
> call do_syscall_trace_exit
> j ret_from_exception
>
> +#ifdef CONFIG_VMAP_STACK
> +handle_kernel_stack_overflow:
> + la sp, shadow_stack
> + addi sp, sp, SHADOW_OVERFLOW_STACK_SIZE
> +
> + //save caller register to shadow stack
> + addi sp, sp, -(PT_SIZE_ON_STACK)
> + REG_S x1, PT_RA(sp)
> + REG_S x5, PT_T0(sp)
> + REG_S x6, PT_T1(sp)
> + REG_S x7, PT_T2(sp)
> + REG_S x10, PT_A0(sp)
> + REG_S x11, PT_A1(sp)
> + REG_S x12, PT_A2(sp)
> + REG_S x13, PT_A3(sp)
> + REG_S x14, PT_A4(sp)
> + REG_S x15, PT_A5(sp)
> + REG_S x16, PT_A6(sp)
> + REG_S x17, PT_A7(sp)
> + REG_S x28, PT_T3(sp)
> + REG_S x29, PT_T4(sp)
> + REG_S x30, PT_T5(sp)
> + REG_S x31, PT_T6(sp)
> +
> + la ra, restore_caller_reg
> + tail get_overflow_stack
> +
> +restore_caller_reg:
> + //save per-cpu overflow stack
> + sd a0, -8(sp)
> + //restore caller register from shadow_stack
> + REG_L x1, PT_RA(sp)
> + REG_L x5, PT_T0(sp)
> + REG_L x6, PT_T1(sp)
> + REG_L x7, PT_T2(sp)
> + REG_L x10, PT_A0(sp)
> + REG_L x11, PT_A1(sp)
> + REG_L x12, PT_A2(sp)
> + REG_L x13, PT_A3(sp)
> + REG_L x14, PT_A4(sp)
> + REG_L x15, PT_A5(sp)
> + REG_L x16, PT_A6(sp)
> + REG_L x17, PT_A7(sp)
> + REG_L x28, PT_T3(sp)
> + REG_L x29, PT_T4(sp)
> + REG_L x30, PT_T5(sp)
> + REG_L x31, PT_T6(sp)
> +
> + //load per-cpu overflow stack
> + ld sp, -8(sp)
> + addi sp, sp, -(PT_SIZE_ON_STACK)
> +
> + //save context to overflow stack
> + REG_S x1, PT_RA(sp)
> + REG_S x3, PT_GP(sp)
> + REG_S x5, PT_T0(sp)
> + REG_S x6, PT_T1(sp)
> + REG_S x7, PT_T2(sp)
> + REG_S x8, PT_S0(sp)
> + REG_S x9, PT_S1(sp)
> + REG_S x10, PT_A0(sp)
> + REG_S x11, PT_A1(sp)
> + REG_S x12, PT_A2(sp)
> + REG_S x13, PT_A3(sp)
> + REG_S x14, PT_A4(sp)
> + REG_S x15, PT_A5(sp)
> + REG_S x16, PT_A6(sp)
> + REG_S x17, PT_A7(sp)
> + REG_S x18, PT_S2(sp)
> + REG_S x19, PT_S3(sp)
> + REG_S x20, PT_S4(sp)
> + REG_S x21, PT_S5(sp)
> + REG_S x22, PT_S6(sp)
> + REG_S x23, PT_S7(sp)
> + REG_S x24, PT_S8(sp)
> + REG_S x25, PT_S9(sp)
> + REG_S x26, PT_S10(sp)
> + REG_S x27, PT_S11(sp)
> + REG_S x28, PT_T3(sp)
> + REG_S x29, PT_T4(sp)
> + REG_S x30, PT_T5(sp)
> + REG_S x31, PT_T6(sp)
> +
> + REG_L s0, TASK_TI_KERNEL_SP(tp)
> + csrr s1, CSR_STATUS
> + csrr s2, CSR_EPC
> + csrr s3, CSR_TVAL
> + csrr s4, CSR_CAUSE
> + csrr s5, CSR_SCRATCH
> + REG_S s0, PT_SP(sp)
> + REG_S s1, PT_STATUS(sp)
> + REG_S s2, PT_EPC(sp)
> + REG_S s3, PT_BADADDR(sp)
> + REG_S s4, PT_CAUSE(sp)
> + REG_S s5, PT_TP(sp)
> + move a0, sp
> + tail handle_bad_stack
> +#endif
> +
> END(handle_exception)
>
> ENTRY(ret_from_fork)
> diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
> index 1357abf79570..ff8033b9fdd6 100644
> --- a/arch/riscv/kernel/traps.c
> +++ b/arch/riscv/kernel/traps.c
> @@ -200,3 +200,38 @@ int is_valid_bugaddr(unsigned long pc)
> void trap_init(void)
> {
> }
> +
> +#ifdef CONFIG_VMAP_STACK
> +DEFINE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack)
> + __aligned(16);
> +/*
> + * shadow stack, handled_ kernel_ stack_ overflow(in kernel/entry.S) is used
> + * to get per-cpu overflow stack(get_overflow_stack).
> + */
> +long shadow_stack[SHADOW_OVERFLOW_STACK_SIZE/sizeof(long)];
> +asmlinkage unsigned long get_overflow_stack(void)
> +{
> + return (unsigned long)this_cpu_ptr(overflow_stack) +
> + OVERFLOW_STACK_SIZE;
> +}
> +
> +asmlinkage void handle_bad_stack(struct pt_regs *regs)
> +{
> + unsigned long tsk_stk = (unsigned long)current->stack;
> + unsigned long ovf_stk = (unsigned long)this_cpu_ptr(overflow_stack);
> +
> + console_verbose();
> +
> + pr_emerg("Insufficient stack space to handle exception!\n");
> + pr_emerg("Task stack: [0x%016lx..0x%016lx]\n",
> + tsk_stk, tsk_stk + THREAD_SIZE);
> + pr_emerg("Overflow stack: [0x%016lx..0x%016lx]\n",
> + ovf_stk, ovf_stk + OVERFLOW_STACK_SIZE);
> +
> + __show_regs(regs);
> + panic("Kernel stack overflow");
> +
> + for (;;)
> + wait_for_interrupt();
> +}
> +#endif
This LGTM. It seems good enough to take, I'm not sure why this is an
RFC?
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH] riscv: add VMAP_STACK overflow detection
2021-05-23 1:49 ` Palmer Dabbelt
@ 2021-05-24 13:51 ` tongtiangen
-1 siblings, 0 replies; 9+ messages in thread
From: tongtiangen @ 2021-05-24 13:51 UTC (permalink / raw)
To: Palmer Dabbelt; +Cc: Paul Walmsley, aou, linux-riscv, linux-kernel
On 2021/5/23 9:49, Palmer Dabbelt wrote:
> On Fri, 07 May 2021 02:25:09 PDT (-0700), tongtiangen@huawei.com wrote:
>> This patch adds stack overflow detection to riscv, usable when
>> CONFIG_VMAP_STACK=y.
>>
>> Overflow is detected in kernel exception entry(kernel/entry.S), if
>> the kernel
>> stack is overflow and been detected, the overflow handler is invoked
>> on a
>> per-cpu overflow stack. This approach preserves GPRs and the original
>> exception
>> information.
>>
>> The overflow detect is performed before any attempt is made to access
>> the stack
>> and the principle of stack overflow detection: kernel stacks are
>> aligned to
>> double their size, enabling overflow to be detected with a single bit
>> test. For
>> example, a 16K stack is aligned to 32K, ensuring that bit 14 of the
>> SP must be
>> zero. On an overflow (or underflow), this bit is flipped. Thus,
>> overflow (of
>> less than the size of the stack) can be detected by testing whether
>> this bit is
>> set.
>>
>> This gives us a useful error message on stack overflow, as can be
>> trigger with
>> the LKDTM overflow test:
>>
>> [ 388.053267] lkdtm: Performing direct entry EXHAUST_STACK
>> [ 388.053663] lkdtm: Calling function with 1024 frame size to depth
>> 32 ...
>> [ 388.054016] lkdtm: loop 32/32 ...
>> [ 388.054186] lkdtm: loop 31/32 ...
>> [ 388.054491] lkdtm: loop 30/32 ...
>> [ 388.054672] lkdtm: loop 29/32 ...
>> [ 388.054859] lkdtm: loop 28/32 ...
>> [ 388.055010] lkdtm: loop 27/32 ...
>> [ 388.055163] lkdtm: loop 26/32 ...
>> [ 388.055309] lkdtm: loop 25/32 ...
>> [ 388.055481] lkdtm: loop 24/32 ...
>> [ 388.055653] lkdtm: loop 23/32 ...
>> [ 388.055837] lkdtm: loop 22/32 ...
>> [ 388.056015] lkdtm: loop 21/32 ...
>> [ 388.056188] lkdtm: loop 20/32 ...
>> [ 388.058145] Insufficient stack space to handle exception!
>> [ 388.058153] Task stack: [0xffffffd014260000..0xffffffd014264000]
>> [ 388.058160] Overflow stack: [0xffffffe1f8d2c220..0xffffffe1f8d2d220]
>> [ 388.058168] CPU: 0 PID: 89 Comm: bash Not tainted 5.12.0-rc8-dirty
>> #90
>> [ 388.058175] Hardware name: riscv-virtio,qemu (DT)
>> [ 388.058187] epc : number+0x32/0x2c0
>> [ 388.058247] ra : vsnprintf+0x2ae/0x3f0
>> [ 388.058255] epc : ffffffe0002d38f6 ra : ffffffe0002d814e sp :
>> ffffffd01425ffc0
>> [ 388.058263] gp : ffffffe0012e4010 tp : ffffffe08014da00 t0 :
>> ffffffd0142606e8
>> [ 388.058271] t1 : 0000000000000000 t2 : 0000000000000000 s0 :
>> ffffffd014260070
>> [ 388.058303] s1 : ffffffd014260158 a0 : ffffffd01426015e a1 :
>> ffffffd014260158
>> [ 388.058311] a2 : 0000000000000013 a3 : ffff0a01ffffff10 a4 :
>> ffffffe000c398e0
>> [ 388.058319] a5 : 511b02ec65f3e300 a6 : 0000000000a1749a a7 :
>> 0000000000000000
>> [ 388.058327] s2 : ffffffff000000ff s3 : 00000000ffff0a01 s4 :
>> ffffffe0012e50a8
>> [ 388.058335] s5 : 0000000000ffff0a s6 : ffffffe0012e50a8 s7 :
>> ffffffe000da1cc0
>> [ 388.058343] s8 : ffffffffffffffff s9 : ffffffd0142602b0 s10:
>> ffffffd0142602a8
>> [ 388.058351] s11: ffffffd01426015e t3 : 00000000000f0000 t4 :
>> ffffffffffffffff
>> [ 388.058359] t5 : 000000000000002f t6 : ffffffd014260158
>> [ 388.058366] status: 0000000000000100 badaddr: ffffffd01425fff8
>> cause: 000000000000000f
>> [ 388.058374] Kernel panic - not syncing: Kernel stack overflow
>> [ 388.058381] CPU: 0 PID: 89 Comm: bash Not tainted 5.12.0-rc8-dirty
>> #90
>> [ 388.058387] Hardware name: riscv-virtio,qemu (DT)
>> [ 388.058393] Call Trace:
>> [ 388.058400] [<ffffffe000004944>] walk_stackframe+0x0/0xce
>> [ 388.058406] [<ffffffe0006f0b28>] dump_backtrace+0x38/0x46
>> [ 388.058412] [<ffffffe0006f0b46>] show_stack+0x10/0x18
>> [ 388.058418] [<ffffffe0006f3690>] dump_stack+0x74/0x8e
>> [ 388.058424] [<ffffffe0006f0d52>] panic+0xfc/0x2b2
>> [ 388.058430] [<ffffffe0006f0acc>] print_trace_address+0x0/0x24
>> [ 388.058436] [<ffffffe0002d814e>] vsnprintf+0x2ae/0x3f0
>> [ 388.058956] SMP: stopping secondary CPUs
>>
>> Signed-off-by: Tong Tiangen <tongtiangen@huawei.com>
>> ---
>> arch/riscv/Kconfig | 1 +
>> arch/riscv/include/asm/thread_info.h | 15 ++++
>> arch/riscv/kernel/entry.S | 108 +++++++++++++++++++++++++++
>> arch/riscv/kernel/traps.c | 35 +++++++++
>> 4 files changed, 159 insertions(+)
>>
>> diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
>> index 4515a10c5d22..587f001e84f4 100644
>> --- a/arch/riscv/Kconfig
>> +++ b/arch/riscv/Kconfig
>> @@ -63,6 +63,7 @@ config RISCV
>> select HAVE_ARCH_MMAP_RND_BITS if MMU
>> select HAVE_ARCH_SECCOMP_FILTER
>> select HAVE_ARCH_TRACEHOOK
>> + select HAVE_ARCH_VMAP_STACK
>> select HAVE_ASM_MODVERSIONS
>> select HAVE_CONTEXT_TRACKING
>> select HAVE_DEBUG_KMEMLEAK
>> diff --git a/arch/riscv/include/asm/thread_info.h
>> b/arch/riscv/include/asm/thread_info.h
>> index 0e549a3089b3..60da0dcacf14 100644
>> --- a/arch/riscv/include/asm/thread_info.h
>> +++ b/arch/riscv/include/asm/thread_info.h
>> @@ -19,6 +19,21 @@
>> #endif
>> #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
>>
>> +/*
>> + * By aligning VMAP'd stacks to 2 * THREAD_SIZE, we can detect
>> overflow by
>> + * checking sp & (1 << THREAD_SHIFT), which we can do cheaply in the
>> entry
>> + * assembly.
>> + */
>> +#ifdef CONFIG_VMAP_STACK
>> +#define THREAD_ALIGN (2 * THREAD_SIZE)
>> +#else
>> +#define THREAD_ALIGN THREAD_SIZE
>> +#endif
>> +
>> +#define THREAD_SHIFT (PAGE_SHIFT + THREAD_SIZE_ORDER)
>> +#define OVERFLOW_STACK_SIZE SZ_4K
>> +#define SHADOW_OVERFLOW_STACK_SIZE (1024)
>> +
>> #ifndef __ASSEMBLY__
>>
>> #include <asm/processor.h>
>> diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
>> index 83095faa680e..deadf4000b86 100644
>> --- a/arch/riscv/kernel/entry.S
>> +++ b/arch/riscv/kernel/entry.S
>> @@ -29,6 +29,15 @@ ENTRY(handle_exception)
>> _restore_kernel_tpsp:
>> csrr tp, CSR_SCRATCH
>> REG_S sp, TASK_TI_KERNEL_SP(tp)
>> +
>> +#ifdef CONFIG_VMAP_STACK
>> + addi sp, sp, -(PT_SIZE_ON_STACK)
>> + srli sp, sp, THREAD_SHIFT
>> + andi sp, sp, 0x1
>> + bnez sp, handle_kernel_stack_overflow
>> + REG_L sp, TASK_TI_KERNEL_SP(tp)
>> +#endif
>> +
>> _save_context:
>> REG_S sp, TASK_TI_USER_SP(tp)
>> REG_L sp, TASK_TI_KERNEL_SP(tp)
>> @@ -375,6 +384,105 @@ handle_syscall_trace_exit:
>> call do_syscall_trace_exit
>> j ret_from_exception
>>
>> +#ifdef CONFIG_VMAP_STACK
>> +handle_kernel_stack_overflow:
>> + la sp, shadow_stack
>> + addi sp, sp, SHADOW_OVERFLOW_STACK_SIZE
>> +
>> + //save caller register to shadow stack
>> + addi sp, sp, -(PT_SIZE_ON_STACK)
>> + REG_S x1, PT_RA(sp)
>> + REG_S x5, PT_T0(sp)
>> + REG_S x6, PT_T1(sp)
>> + REG_S x7, PT_T2(sp)
>> + REG_S x10, PT_A0(sp)
>> + REG_S x11, PT_A1(sp)
>> + REG_S x12, PT_A2(sp)
>> + REG_S x13, PT_A3(sp)
>> + REG_S x14, PT_A4(sp)
>> + REG_S x15, PT_A5(sp)
>> + REG_S x16, PT_A6(sp)
>> + REG_S x17, PT_A7(sp)
>> + REG_S x28, PT_T3(sp)
>> + REG_S x29, PT_T4(sp)
>> + REG_S x30, PT_T5(sp)
>> + REG_S x31, PT_T6(sp)
>> +
>> + la ra, restore_caller_reg
>> + tail get_overflow_stack
>> +
>> +restore_caller_reg:
>> + //save per-cpu overflow stack
>> + sd a0, -8(sp)
>> + //restore caller register from shadow_stack
>> + REG_L x1, PT_RA(sp)
>> + REG_L x5, PT_T0(sp)
>> + REG_L x6, PT_T1(sp)
>> + REG_L x7, PT_T2(sp)
>> + REG_L x10, PT_A0(sp)
>> + REG_L x11, PT_A1(sp)
>> + REG_L x12, PT_A2(sp)
>> + REG_L x13, PT_A3(sp)
>> + REG_L x14, PT_A4(sp)
>> + REG_L x15, PT_A5(sp)
>> + REG_L x16, PT_A6(sp)
>> + REG_L x17, PT_A7(sp)
>> + REG_L x28, PT_T3(sp)
>> + REG_L x29, PT_T4(sp)
>> + REG_L x30, PT_T5(sp)
>> + REG_L x31, PT_T6(sp)
>> +
>> + //load per-cpu overflow stack
>> + ld sp, -8(sp)
>> + addi sp, sp, -(PT_SIZE_ON_STACK)
>> +
>> + //save context to overflow stack
>> + REG_S x1, PT_RA(sp)
>> + REG_S x3, PT_GP(sp)
>> + REG_S x5, PT_T0(sp)
>> + REG_S x6, PT_T1(sp)
>> + REG_S x7, PT_T2(sp)
>> + REG_S x8, PT_S0(sp)
>> + REG_S x9, PT_S1(sp)
>> + REG_S x10, PT_A0(sp)
>> + REG_S x11, PT_A1(sp)
>> + REG_S x12, PT_A2(sp)
>> + REG_S x13, PT_A3(sp)
>> + REG_S x14, PT_A4(sp)
>> + REG_S x15, PT_A5(sp)
>> + REG_S x16, PT_A6(sp)
>> + REG_S x17, PT_A7(sp)
>> + REG_S x18, PT_S2(sp)
>> + REG_S x19, PT_S3(sp)
>> + REG_S x20, PT_S4(sp)
>> + REG_S x21, PT_S5(sp)
>> + REG_S x22, PT_S6(sp)
>> + REG_S x23, PT_S7(sp)
>> + REG_S x24, PT_S8(sp)
>> + REG_S x25, PT_S9(sp)
>> + REG_S x26, PT_S10(sp)
>> + REG_S x27, PT_S11(sp)
>> + REG_S x28, PT_T3(sp)
>> + REG_S x29, PT_T4(sp)
>> + REG_S x30, PT_T5(sp)
>> + REG_S x31, PT_T6(sp)
>> +
>> + REG_L s0, TASK_TI_KERNEL_SP(tp)
>> + csrr s1, CSR_STATUS
>> + csrr s2, CSR_EPC
>> + csrr s3, CSR_TVAL
>> + csrr s4, CSR_CAUSE
>> + csrr s5, CSR_SCRATCH
>> + REG_S s0, PT_SP(sp)
>> + REG_S s1, PT_STATUS(sp)
>> + REG_S s2, PT_EPC(sp)
>> + REG_S s3, PT_BADADDR(sp)
>> + REG_S s4, PT_CAUSE(sp)
>> + REG_S s5, PT_TP(sp)
>> + move a0, sp
>> + tail handle_bad_stack
>> +#endif
>> +
>> END(handle_exception)
>>
>> ENTRY(ret_from_fork)
>> diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
>> index 1357abf79570..ff8033b9fdd6 100644
>> --- a/arch/riscv/kernel/traps.c
>> +++ b/arch/riscv/kernel/traps.c
>> @@ -200,3 +200,38 @@ int is_valid_bugaddr(unsigned long pc)
>> void trap_init(void)
>> {
>> }
>> +
>> +#ifdef CONFIG_VMAP_STACK
>> +DEFINE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)],
>> overflow_stack)
>> + __aligned(16);
>> +/*
>> + * shadow stack, handled_ kernel_ stack_ overflow(in kernel/entry.S)
>> is used
>> + * to get per-cpu overflow stack(get_overflow_stack).
>> + */
>> +long shadow_stack[SHADOW_OVERFLOW_STACK_SIZE/sizeof(long)];
>> +asmlinkage unsigned long get_overflow_stack(void)
>> +{
>> + return (unsigned long)this_cpu_ptr(overflow_stack) +
>> + OVERFLOW_STACK_SIZE;
>> +}
>> +
>> +asmlinkage void handle_bad_stack(struct pt_regs *regs)
>> +{
>> + unsigned long tsk_stk = (unsigned long)current->stack;
>> + unsigned long ovf_stk = (unsigned
>> long)this_cpu_ptr(overflow_stack);
>> +
>> + console_verbose();
>> +
>> + pr_emerg("Insufficient stack space to handle exception!\n");
>> + pr_emerg("Task stack: [0x%016lx..0x%016lx]\n",
>> + tsk_stk, tsk_stk + THREAD_SIZE);
>> + pr_emerg("Overflow stack: [0x%016lx..0x%016lx]\n",
>> + ovf_stk, ovf_stk + OVERFLOW_STACK_SIZE);
>> +
>> + __show_regs(regs);
>> + panic("Kernel stack overflow");
>> +
>> + for (;;)
>> + wait_for_interrupt();
>> +}
>> +#endif
>
> This LGTM. It seems good enough to take, I'm not sure why this is an
> RFC?
> .
Thank you for your reply.
The purpose of my RFC is that I don't think the scheme of getting
per-cpu overflow stack is optimal.
At present, the patch based on next has been issued.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH] riscv: add VMAP_STACK overflow detection
@ 2021-05-24 13:51 ` tongtiangen
0 siblings, 0 replies; 9+ messages in thread
From: tongtiangen @ 2021-05-24 13:51 UTC (permalink / raw)
To: Palmer Dabbelt; +Cc: Paul Walmsley, aou, linux-riscv, linux-kernel
On 2021/5/23 9:49, Palmer Dabbelt wrote:
> On Fri, 07 May 2021 02:25:09 PDT (-0700), tongtiangen@huawei.com wrote:
>> This patch adds stack overflow detection to riscv, usable when
>> CONFIG_VMAP_STACK=y.
>>
>> Overflow is detected in kernel exception entry(kernel/entry.S), if
>> the kernel
>> stack is overflow and been detected, the overflow handler is invoked
>> on a
>> per-cpu overflow stack. This approach preserves GPRs and the original
>> exception
>> information.
>>
>> The overflow detect is performed before any attempt is made to access
>> the stack
>> and the principle of stack overflow detection: kernel stacks are
>> aligned to
>> double their size, enabling overflow to be detected with a single bit
>> test. For
>> example, a 16K stack is aligned to 32K, ensuring that bit 14 of the
>> SP must be
>> zero. On an overflow (or underflow), this bit is flipped. Thus,
>> overflow (of
>> less than the size of the stack) can be detected by testing whether
>> this bit is
>> set.
>>
>> This gives us a useful error message on stack overflow, as can be
>> trigger with
>> the LKDTM overflow test:
>>
>> [ 388.053267] lkdtm: Performing direct entry EXHAUST_STACK
>> [ 388.053663] lkdtm: Calling function with 1024 frame size to depth
>> 32 ...
>> [ 388.054016] lkdtm: loop 32/32 ...
>> [ 388.054186] lkdtm: loop 31/32 ...
>> [ 388.054491] lkdtm: loop 30/32 ...
>> [ 388.054672] lkdtm: loop 29/32 ...
>> [ 388.054859] lkdtm: loop 28/32 ...
>> [ 388.055010] lkdtm: loop 27/32 ...
>> [ 388.055163] lkdtm: loop 26/32 ...
>> [ 388.055309] lkdtm: loop 25/32 ...
>> [ 388.055481] lkdtm: loop 24/32 ...
>> [ 388.055653] lkdtm: loop 23/32 ...
>> [ 388.055837] lkdtm: loop 22/32 ...
>> [ 388.056015] lkdtm: loop 21/32 ...
>> [ 388.056188] lkdtm: loop 20/32 ...
>> [ 388.058145] Insufficient stack space to handle exception!
>> [ 388.058153] Task stack: [0xffffffd014260000..0xffffffd014264000]
>> [ 388.058160] Overflow stack: [0xffffffe1f8d2c220..0xffffffe1f8d2d220]
>> [ 388.058168] CPU: 0 PID: 89 Comm: bash Not tainted 5.12.0-rc8-dirty
>> #90
>> [ 388.058175] Hardware name: riscv-virtio,qemu (DT)
>> [ 388.058187] epc : number+0x32/0x2c0
>> [ 388.058247] ra : vsnprintf+0x2ae/0x3f0
>> [ 388.058255] epc : ffffffe0002d38f6 ra : ffffffe0002d814e sp :
>> ffffffd01425ffc0
>> [ 388.058263] gp : ffffffe0012e4010 tp : ffffffe08014da00 t0 :
>> ffffffd0142606e8
>> [ 388.058271] t1 : 0000000000000000 t2 : 0000000000000000 s0 :
>> ffffffd014260070
>> [ 388.058303] s1 : ffffffd014260158 a0 : ffffffd01426015e a1 :
>> ffffffd014260158
>> [ 388.058311] a2 : 0000000000000013 a3 : ffff0a01ffffff10 a4 :
>> ffffffe000c398e0
>> [ 388.058319] a5 : 511b02ec65f3e300 a6 : 0000000000a1749a a7 :
>> 0000000000000000
>> [ 388.058327] s2 : ffffffff000000ff s3 : 00000000ffff0a01 s4 :
>> ffffffe0012e50a8
>> [ 388.058335] s5 : 0000000000ffff0a s6 : ffffffe0012e50a8 s7 :
>> ffffffe000da1cc0
>> [ 388.058343] s8 : ffffffffffffffff s9 : ffffffd0142602b0 s10:
>> ffffffd0142602a8
>> [ 388.058351] s11: ffffffd01426015e t3 : 00000000000f0000 t4 :
>> ffffffffffffffff
>> [ 388.058359] t5 : 000000000000002f t6 : ffffffd014260158
>> [ 388.058366] status: 0000000000000100 badaddr: ffffffd01425fff8
>> cause: 000000000000000f
>> [ 388.058374] Kernel panic - not syncing: Kernel stack overflow
>> [ 388.058381] CPU: 0 PID: 89 Comm: bash Not tainted 5.12.0-rc8-dirty
>> #90
>> [ 388.058387] Hardware name: riscv-virtio,qemu (DT)
>> [ 388.058393] Call Trace:
>> [ 388.058400] [<ffffffe000004944>] walk_stackframe+0x0/0xce
>> [ 388.058406] [<ffffffe0006f0b28>] dump_backtrace+0x38/0x46
>> [ 388.058412] [<ffffffe0006f0b46>] show_stack+0x10/0x18
>> [ 388.058418] [<ffffffe0006f3690>] dump_stack+0x74/0x8e
>> [ 388.058424] [<ffffffe0006f0d52>] panic+0xfc/0x2b2
>> [ 388.058430] [<ffffffe0006f0acc>] print_trace_address+0x0/0x24
>> [ 388.058436] [<ffffffe0002d814e>] vsnprintf+0x2ae/0x3f0
>> [ 388.058956] SMP: stopping secondary CPUs
>>
>> Signed-off-by: Tong Tiangen <tongtiangen@huawei.com>
>> ---
>> arch/riscv/Kconfig | 1 +
>> arch/riscv/include/asm/thread_info.h | 15 ++++
>> arch/riscv/kernel/entry.S | 108 +++++++++++++++++++++++++++
>> arch/riscv/kernel/traps.c | 35 +++++++++
>> 4 files changed, 159 insertions(+)
>>
>> diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
>> index 4515a10c5d22..587f001e84f4 100644
>> --- a/arch/riscv/Kconfig
>> +++ b/arch/riscv/Kconfig
>> @@ -63,6 +63,7 @@ config RISCV
>> select HAVE_ARCH_MMAP_RND_BITS if MMU
>> select HAVE_ARCH_SECCOMP_FILTER
>> select HAVE_ARCH_TRACEHOOK
>> + select HAVE_ARCH_VMAP_STACK
>> select HAVE_ASM_MODVERSIONS
>> select HAVE_CONTEXT_TRACKING
>> select HAVE_DEBUG_KMEMLEAK
>> diff --git a/arch/riscv/include/asm/thread_info.h
>> b/arch/riscv/include/asm/thread_info.h
>> index 0e549a3089b3..60da0dcacf14 100644
>> --- a/arch/riscv/include/asm/thread_info.h
>> +++ b/arch/riscv/include/asm/thread_info.h
>> @@ -19,6 +19,21 @@
>> #endif
>> #define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
>>
>> +/*
>> + * By aligning VMAP'd stacks to 2 * THREAD_SIZE, we can detect
>> overflow by
>> + * checking sp & (1 << THREAD_SHIFT), which we can do cheaply in the
>> entry
>> + * assembly.
>> + */
>> +#ifdef CONFIG_VMAP_STACK
>> +#define THREAD_ALIGN (2 * THREAD_SIZE)
>> +#else
>> +#define THREAD_ALIGN THREAD_SIZE
>> +#endif
>> +
>> +#define THREAD_SHIFT (PAGE_SHIFT + THREAD_SIZE_ORDER)
>> +#define OVERFLOW_STACK_SIZE SZ_4K
>> +#define SHADOW_OVERFLOW_STACK_SIZE (1024)
>> +
>> #ifndef __ASSEMBLY__
>>
>> #include <asm/processor.h>
>> diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
>> index 83095faa680e..deadf4000b86 100644
>> --- a/arch/riscv/kernel/entry.S
>> +++ b/arch/riscv/kernel/entry.S
>> @@ -29,6 +29,15 @@ ENTRY(handle_exception)
>> _restore_kernel_tpsp:
>> csrr tp, CSR_SCRATCH
>> REG_S sp, TASK_TI_KERNEL_SP(tp)
>> +
>> +#ifdef CONFIG_VMAP_STACK
>> + addi sp, sp, -(PT_SIZE_ON_STACK)
>> + srli sp, sp, THREAD_SHIFT
>> + andi sp, sp, 0x1
>> + bnez sp, handle_kernel_stack_overflow
>> + REG_L sp, TASK_TI_KERNEL_SP(tp)
>> +#endif
>> +
>> _save_context:
>> REG_S sp, TASK_TI_USER_SP(tp)
>> REG_L sp, TASK_TI_KERNEL_SP(tp)
>> @@ -375,6 +384,105 @@ handle_syscall_trace_exit:
>> call do_syscall_trace_exit
>> j ret_from_exception
>>
>> +#ifdef CONFIG_VMAP_STACK
>> +handle_kernel_stack_overflow:
>> + la sp, shadow_stack
>> + addi sp, sp, SHADOW_OVERFLOW_STACK_SIZE
>> +
>> + //save caller register to shadow stack
>> + addi sp, sp, -(PT_SIZE_ON_STACK)
>> + REG_S x1, PT_RA(sp)
>> + REG_S x5, PT_T0(sp)
>> + REG_S x6, PT_T1(sp)
>> + REG_S x7, PT_T2(sp)
>> + REG_S x10, PT_A0(sp)
>> + REG_S x11, PT_A1(sp)
>> + REG_S x12, PT_A2(sp)
>> + REG_S x13, PT_A3(sp)
>> + REG_S x14, PT_A4(sp)
>> + REG_S x15, PT_A5(sp)
>> + REG_S x16, PT_A6(sp)
>> + REG_S x17, PT_A7(sp)
>> + REG_S x28, PT_T3(sp)
>> + REG_S x29, PT_T4(sp)
>> + REG_S x30, PT_T5(sp)
>> + REG_S x31, PT_T6(sp)
>> +
>> + la ra, restore_caller_reg
>> + tail get_overflow_stack
>> +
>> +restore_caller_reg:
>> + //save per-cpu overflow stack
>> + sd a0, -8(sp)
>> + //restore caller register from shadow_stack
>> + REG_L x1, PT_RA(sp)
>> + REG_L x5, PT_T0(sp)
>> + REG_L x6, PT_T1(sp)
>> + REG_L x7, PT_T2(sp)
>> + REG_L x10, PT_A0(sp)
>> + REG_L x11, PT_A1(sp)
>> + REG_L x12, PT_A2(sp)
>> + REG_L x13, PT_A3(sp)
>> + REG_L x14, PT_A4(sp)
>> + REG_L x15, PT_A5(sp)
>> + REG_L x16, PT_A6(sp)
>> + REG_L x17, PT_A7(sp)
>> + REG_L x28, PT_T3(sp)
>> + REG_L x29, PT_T4(sp)
>> + REG_L x30, PT_T5(sp)
>> + REG_L x31, PT_T6(sp)
>> +
>> + //load per-cpu overflow stack
>> + ld sp, -8(sp)
>> + addi sp, sp, -(PT_SIZE_ON_STACK)
>> +
>> + //save context to overflow stack
>> + REG_S x1, PT_RA(sp)
>> + REG_S x3, PT_GP(sp)
>> + REG_S x5, PT_T0(sp)
>> + REG_S x6, PT_T1(sp)
>> + REG_S x7, PT_T2(sp)
>> + REG_S x8, PT_S0(sp)
>> + REG_S x9, PT_S1(sp)
>> + REG_S x10, PT_A0(sp)
>> + REG_S x11, PT_A1(sp)
>> + REG_S x12, PT_A2(sp)
>> + REG_S x13, PT_A3(sp)
>> + REG_S x14, PT_A4(sp)
>> + REG_S x15, PT_A5(sp)
>> + REG_S x16, PT_A6(sp)
>> + REG_S x17, PT_A7(sp)
>> + REG_S x18, PT_S2(sp)
>> + REG_S x19, PT_S3(sp)
>> + REG_S x20, PT_S4(sp)
>> + REG_S x21, PT_S5(sp)
>> + REG_S x22, PT_S6(sp)
>> + REG_S x23, PT_S7(sp)
>> + REG_S x24, PT_S8(sp)
>> + REG_S x25, PT_S9(sp)
>> + REG_S x26, PT_S10(sp)
>> + REG_S x27, PT_S11(sp)
>> + REG_S x28, PT_T3(sp)
>> + REG_S x29, PT_T4(sp)
>> + REG_S x30, PT_T5(sp)
>> + REG_S x31, PT_T6(sp)
>> +
>> + REG_L s0, TASK_TI_KERNEL_SP(tp)
>> + csrr s1, CSR_STATUS
>> + csrr s2, CSR_EPC
>> + csrr s3, CSR_TVAL
>> + csrr s4, CSR_CAUSE
>> + csrr s5, CSR_SCRATCH
>> + REG_S s0, PT_SP(sp)
>> + REG_S s1, PT_STATUS(sp)
>> + REG_S s2, PT_EPC(sp)
>> + REG_S s3, PT_BADADDR(sp)
>> + REG_S s4, PT_CAUSE(sp)
>> + REG_S s5, PT_TP(sp)
>> + move a0, sp
>> + tail handle_bad_stack
>> +#endif
>> +
>> END(handle_exception)
>>
>> ENTRY(ret_from_fork)
>> diff --git a/arch/riscv/kernel/traps.c b/arch/riscv/kernel/traps.c
>> index 1357abf79570..ff8033b9fdd6 100644
>> --- a/arch/riscv/kernel/traps.c
>> +++ b/arch/riscv/kernel/traps.c
>> @@ -200,3 +200,38 @@ int is_valid_bugaddr(unsigned long pc)
>> void trap_init(void)
>> {
>> }
>> +
>> +#ifdef CONFIG_VMAP_STACK
>> +DEFINE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)],
>> overflow_stack)
>> + __aligned(16);
>> +/*
>> + * shadow stack, handled_ kernel_ stack_ overflow(in kernel/entry.S)
>> is used
>> + * to get per-cpu overflow stack(get_overflow_stack).
>> + */
>> +long shadow_stack[SHADOW_OVERFLOW_STACK_SIZE/sizeof(long)];
>> +asmlinkage unsigned long get_overflow_stack(void)
>> +{
>> + return (unsigned long)this_cpu_ptr(overflow_stack) +
>> + OVERFLOW_STACK_SIZE;
>> +}
>> +
>> +asmlinkage void handle_bad_stack(struct pt_regs *regs)
>> +{
>> + unsigned long tsk_stk = (unsigned long)current->stack;
>> + unsigned long ovf_stk = (unsigned
>> long)this_cpu_ptr(overflow_stack);
>> +
>> + console_verbose();
>> +
>> + pr_emerg("Insufficient stack space to handle exception!\n");
>> + pr_emerg("Task stack: [0x%016lx..0x%016lx]\n",
>> + tsk_stk, tsk_stk + THREAD_SIZE);
>> + pr_emerg("Overflow stack: [0x%016lx..0x%016lx]\n",
>> + ovf_stk, ovf_stk + OVERFLOW_STACK_SIZE);
>> +
>> + __show_regs(regs);
>> + panic("Kernel stack overflow");
>> +
>> + for (;;)
>> + wait_for_interrupt();
>> +}
>> +#endif
>
> This LGTM. It seems good enough to take, I'm not sure why this is an
> RFC?
> .
Thank you for your reply.
The purpose of my RFC is that I don't think the scheme of getting
per-cpu overflow stack is optimal.
At present, the patch based on next has been issued.
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2021-05-24 22:43 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-07 9:25 [RFC PATCH] riscv: add VMAP_STACK overflow detection Tong Tiangen
2021-05-07 9:25 ` Tong Tiangen
2021-05-07 12:00 ` kernel test robot
2021-05-07 12:37 ` kernel test robot
2021-05-07 13:22 ` kernel test robot
2021-05-23 1:49 ` Palmer Dabbelt
2021-05-23 1:49 ` Palmer Dabbelt
2021-05-24 13:51 ` tongtiangen
2021-05-24 13:51 ` tongtiangen
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.