Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

riscv: Support RANDOMIZE_KSTACK_OFFSET

Inspired from arm64's implement -- commit 70918779aec9
("arm64: entry: Enable random_kstack_offset support")

Add support of kernel stack offset randomization while handling syscall,
the offset is defaultly limited by KSTACK_OFFSET_MAX() (i.e. 10 bits).

In order to avoid trigger stack canaries (due to __builtin_alloca) and
slowing down the entry path, use __no_stack_protector attribute to
disable stack protector for do_trap_ecall_u() at the function level.

Acked-by: Palmer Dabbelt <palmer@rivosinc.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Song Shuai <songshuaishuai@tinylab.org>
Link: https://lore.kernel.org/r/20231109133751.212079-1-songshuaishuai@tinylab.org
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>

authored by

Song Shuai and committed by
Palmer Dabbelt
05d450aa dded618c

+17 -1
+1
arch/riscv/Kconfig
··· 109 109 select HAVE_ARCH_KGDB_QXFER_PKT 110 110 select HAVE_ARCH_MMAP_RND_BITS if MMU 111 111 select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPAT 112 + select HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET 112 113 select HAVE_ARCH_SECCOMP_FILTER 113 114 select HAVE_ARCH_THREAD_STRUCT_WHITELIST 114 115 select HAVE_ARCH_TRACEHOOK
+16 -1
arch/riscv/kernel/traps.c
··· 6 6 #include <linux/cpu.h> 7 7 #include <linux/kernel.h> 8 8 #include <linux/init.h> 9 + #include <linux/randomize_kstack.h> 9 10 #include <linux/sched.h> 10 11 #include <linux/sched/debug.h> 11 12 #include <linux/sched/signal.h> ··· 311 310 } 312 311 } 313 312 314 - asmlinkage __visible __trap_section void do_trap_ecall_u(struct pt_regs *regs) 313 + asmlinkage __visible __trap_section __no_stack_protector 314 + void do_trap_ecall_u(struct pt_regs *regs) 315 315 { 316 316 if (user_mode(regs)) { 317 317 long syscall = regs->a7; ··· 324 322 325 323 syscall = syscall_enter_from_user_mode(regs, syscall); 326 324 325 + add_random_kstack_offset(); 326 + 327 327 if (syscall >= 0 && syscall < NR_syscalls) 328 328 syscall_handler(regs, syscall); 329 329 else if (syscall != -1) 330 330 regs->a0 = -ENOSYS; 331 + /* 332 + * Ultimately, this value will get limited by KSTACK_OFFSET_MAX(), 333 + * so the maximum stack offset is 1k bytes (10 bits). 334 + * 335 + * The actual entropy will be further reduced by the compiler when 336 + * applying stack alignment constraints: 16-byte (i.e. 4-bit) aligned 337 + * for RV32I or RV64I. 338 + * 339 + * The resulting 6 bits of entropy is seen in SP[9:4]. 340 + */ 341 + choose_random_kstack_offset(get_random_u16()); 331 342 332 343 syscall_exit_to_user_mode(regs); 333 344 } else {