Unverified Commit d1584d79 authored by Sami Tolvanen's avatar Sami Tolvanen Committed by Palmer Dabbelt
Browse files

riscv: Implement Shadow Call Stack



Implement CONFIG_SHADOW_CALL_STACK for RISC-V. When enabled, the
compiler injects instructions to all non-leaf C functions to
store the return address to the shadow stack and unconditionally
load it again before returning, which makes it harder to corrupt
the return address through a stack overflow, for example.

The active shadow call stack pointer is stored in the gp
register, which makes SCS incompatible with gp relaxation. Use
--no-relax-gp to ensure gp relaxation is disabled and disable
global pointer loading.  Add SCS pointers to struct thread_info,
implement SCS initialization, and task switching

Signed-off-by: default avatarSami Tolvanen <samitolvanen@google.com>
Tested-by: default avatarNathan Chancellor <nathan@kernel.org>
Link: https://lore.kernel.org/r/20230927224757.1154247-12-samitolvanen@google.com


Signed-off-by: default avatarPalmer Dabbelt <palmer@rivosinc.com>
parent e609b4f4
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ config RISCV
	select ARCH_SUPPORTS_HUGETLBFS if MMU
	select ARCH_SUPPORTS_PAGE_TABLE_CHECK if MMU
	select ARCH_SUPPORTS_PER_VMA_LOCK if MMU
	select ARCH_SUPPORTS_SHADOW_CALL_STACK if HAVE_SHADOW_CALL_STACK
	select ARCH_USE_MEMTEST
	select ARCH_USE_QUEUED_RWLOCKS
	select ARCH_USES_CFI_TRAPS if CFI_CLANG
@@ -174,6 +175,11 @@ config GCC_SUPPORTS_DYNAMIC_FTRACE
	def_bool CC_IS_GCC
	depends on $(cc-option,-fpatchable-function-entry=8)

config HAVE_SHADOW_CALL_STACK
	def_bool $(cc-option,-fsanitize=shadow-call-stack)
	# https://github.com/riscv-non-isa/riscv-elf-psabi-doc/commit/a484e843e6eeb51f0cb7b8819e50da6d2444d769
	depends on $(ld-option,--no-relax-gp)

config ARCH_MMAP_RND_BITS_MIN
	default 18 if 64BIT
	default 8
+4 −0
Original line number Diff line number Diff line
@@ -55,6 +55,10 @@ endif
endif
endif

ifeq ($(CONFIG_SHADOW_CALL_STACK),y)
	KBUILD_LDFLAGS += --no-relax-gp
endif

# ISA string setting
riscv-march-$(CONFIG_ARCH_RV32I)	:= rv32ima
riscv-march-$(CONFIG_ARCH_RV64I)	:= rv64ima
+6 −0
Original line number Diff line number Diff line
@@ -109,6 +109,11 @@
	REG_L \dst, 0(\dst)
.endm

#ifdef CONFIG_SHADOW_CALL_STACK
/* gp is used as the shadow call stack pointer instead */
.macro load_global_pointer
.endm
#else
/* load __global_pointer to gp */
.macro load_global_pointer
.option push
@@ -116,6 +121,7 @@
	la gp, __global_pointer$
.option pop
.endm
#endif /* CONFIG_SHADOW_CALL_STACK */

	/* save all GPs except x1 ~ x5 */
	.macro save_from_x6_to_x31
+47 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_SCS_H
#define _ASM_SCS_H

#ifdef __ASSEMBLY__
#include <asm/asm-offsets.h>

#ifdef CONFIG_SHADOW_CALL_STACK

/* Load init_shadow_call_stack to gp. */
.macro scs_load_init_stack
	la	gp, init_shadow_call_stack
	XIP_FIXUP_OFFSET gp
.endm

/* Load task_scs_sp(current) to gp. */
.macro scs_load_current
	REG_L	gp, TASK_TI_SCS_SP(tp)
.endm

/* Load task_scs_sp(current) to gp, but only if tp has changed. */
.macro scs_load_current_if_task_changed prev
	beq	\prev, tp, _skip_scs
	scs_load_current
_skip_scs:
.endm

/* Save gp to task_scs_sp(current). */
.macro scs_save_current
	REG_S	gp, TASK_TI_SCS_SP(tp)
.endm

#else /* CONFIG_SHADOW_CALL_STACK */

.macro scs_load_init_stack
.endm
.macro scs_load_current
.endm
.macro scs_load_current_if_task_changed prev
.endm
.macro scs_save_current
.endm

#endif /* CONFIG_SHADOW_CALL_STACK */
#endif /* __ASSEMBLY__ */

#endif /* _ASM_SCS_H */
+13 −0
Original line number Diff line number Diff line
@@ -57,8 +57,20 @@ struct thread_info {
	long			user_sp;	/* User stack pointer */
	int			cpu;
	unsigned long		syscall_work;	/* SYSCALL_WORK_ flags */
#ifdef CONFIG_SHADOW_CALL_STACK
	void			*scs_base;
	void			*scs_sp;
#endif
};

#ifdef CONFIG_SHADOW_CALL_STACK
#define INIT_SCS							\
	.scs_base	= init_shadow_call_stack,			\
	.scs_sp		= init_shadow_call_stack,
#else
#define INIT_SCS
#endif

/*
 * macros/functions for gaining access to the thread information structure
 *
@@ -68,6 +80,7 @@ struct thread_info {
{						\
	.flags		= 0,			\
	.preempt_count	= INIT_PREEMPT_COUNT,	\
	INIT_SCS				\
}

void arch_release_task_struct(struct task_struct *tsk);
Loading