Skip to content

Commit c3ec1e8

Browse files
Merge patch series "RISC-V: Align the shadow stack"
Palmer Dabbelt <[email protected]> says: This contains a pair of cleanups that depend on a fix that has already landed upstream. * b4-shazam-merge: RISC-V: Add some comments about the shadow and overflow stacks RISC-V: Align the shadow stack riscv: fix race when vmap stack overflow Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Palmer Dabbelt <[email protected]>
2 parents d01404f + de57ecc commit c3ec1e8

File tree

3 files changed

+41
-3
lines changed

3 files changed

+41
-3
lines changed

arch/riscv/include/asm/asm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#define REG_L __REG_SEL(ld, lw)
2424
#define REG_S __REG_SEL(sd, sw)
2525
#define REG_SC __REG_SEL(sc.d, sc.w)
26+
#define REG_AMOSWAP_AQ __REG_SEL(amoswap.d.aq, amoswap.w.aq)
2627
#define REG_ASM __REG_SEL(.dword, .word)
2728
#define SZREG __REG_SEL(8, 4)
2829
#define LGREG __REG_SEL(3, 2)

arch/riscv/kernel/entry.S

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,19 @@ handle_syscall_trace_exit:
397397

398398
#ifdef CONFIG_VMAP_STACK
399399
handle_kernel_stack_overflow:
400+
/*
401+
* Takes the psuedo-spinlock for the shadow stack, in case multiple
402+
* harts are concurrently overflowing their kernel stacks. We could
403+
* store any value here, but since we're overflowing the kernel stack
404+
* already we only have SP to use as a scratch register. So we just
405+
* swap in the address of the spinlock, as that's definately non-zero.
406+
*
407+
* Pairs with a store_release in handle_bad_stack().
408+
*/
409+
1: la sp, spin_shadow_stack
410+
REG_AMOSWAP_AQ sp, sp, (sp)
411+
bnez sp, 1b
412+
400413
la sp, shadow_stack
401414
addi sp, sp, SHADOW_OVERFLOW_STACK_SIZE
402415

arch/riscv/kernel/traps.c

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,13 +208,28 @@ int is_valid_bugaddr(unsigned long pc)
208208
#endif /* CONFIG_GENERIC_BUG */
209209

210210
#ifdef CONFIG_VMAP_STACK
211+
/*
212+
* Extra stack space that allows us to provide panic messages when the kernel
213+
* has overflowed its stack.
214+
*/
211215
static DEFINE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)],
212216
overflow_stack)__aligned(16);
213217
/*
214-
* shadow stack, handled_ kernel_ stack_ overflow(in kernel/entry.S) is used
215-
* to get per-cpu overflow stack(get_overflow_stack).
218+
* A temporary stack for use by handle_kernel_stack_overflow. This is used so
219+
* we can call into C code to get the per-hart overflow stack. Usage of this
220+
* stack must be protected by spin_shadow_stack.
216221
*/
217-
long shadow_stack[SHADOW_OVERFLOW_STACK_SIZE/sizeof(long)];
222+
long shadow_stack[SHADOW_OVERFLOW_STACK_SIZE/sizeof(long)] __aligned(16);
223+
224+
/*
225+
* A pseudo spinlock to protect the shadow stack from being used by multiple
226+
* harts concurrently. This isn't a real spinlock because the lock side must
227+
* be taken without a valid stack and only a single register, it's only taken
228+
* while in the process of panicing anyway so the performance and error
229+
* checking a proper spinlock gives us doesn't matter.
230+
*/
231+
unsigned long spin_shadow_stack;
232+
218233
asmlinkage unsigned long get_overflow_stack(void)
219234
{
220235
return (unsigned long)this_cpu_ptr(overflow_stack) +
@@ -226,6 +241,15 @@ asmlinkage void handle_bad_stack(struct pt_regs *regs)
226241
unsigned long tsk_stk = (unsigned long)current->stack;
227242
unsigned long ovf_stk = (unsigned long)this_cpu_ptr(overflow_stack);
228243

244+
/*
245+
* We're done with the shadow stack by this point, as we're on the
246+
* overflow stack. Tell any other concurrent overflowing harts that
247+
* they can proceed with panicing by releasing the pseudo-spinlock.
248+
*
249+
* This pairs with an amoswap.aq in handle_kernel_stack_overflow.
250+
*/
251+
smp_store_release(&spin_shadow_stack, 0);
252+
229253
console_verbose();
230254

231255
pr_emerg("Insufficient stack space to handle exception!\n");

0 commit comments

Comments
 (0)