Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 189af465 authored by Ard Biesheuvel's avatar Ard Biesheuvel Committed by Kees Cook
Browse files

ARM: smp: add support for per-task stack canaries



On ARM, we currently only change the value of the stack canary when
switching tasks if the kernel was built for UP. On SMP kernels, this
is impossible since the stack canary value is obtained via a global
symbol reference, which means
a) all running tasks on all CPUs must use the same value
b) we can only modify the value when no kernel stack frames are live
   on any CPU, which is effectively never.

So instead, use a GCC plugin to add a RTL pass that replaces each
reference to the address of the __stack_chk_guard symbol with an
expression that produces the address of the 'stack_canary' field
that is added to struct thread_info. This way, each task will use
its own randomized value.

Cc: Russell King <linux@armlinux.org.uk>
Cc: Kees Cook <keescook@chromium.org>
Cc: Emese Revfy <re.emese@gmail.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Laura Abbott <labbott@redhat.com>
Cc: kernel-hardening@lists.openwall.com
Acked-by: default avatarNicolas Pitre <nico@linaro.org>
Signed-off-by: default avatarArd Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: default avatarKees Cook <keescook@chromium.org>
parent ccda4af0
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -1810,6 +1810,21 @@ config XEN
	help
	  Say Y if you want to run Linux in a Virtual Machine on Xen on ARM.

config STACKPROTECTOR_PER_TASK
	bool "Use a unique stack canary value for each task"
	depends on GCC_PLUGINS && STACKPROTECTOR && SMP && !XIP_DEFLATED_DATA
	select GCC_PLUGIN_ARM_SSP_PER_TASK
	default y
	help
	  Due to the fact that GCC uses an ordinary symbol reference from
	  which to load the value of the stack canary, this value can only
	  change at reboot time on SMP systems, and all tasks running in the
	  kernel's address space are forced to use the same canary value for
	  the entire duration that the system is up.

	  Enable this option to switch to a different method that uses a
	  different canary value for each task.

endmenu

menu "Boot options"
+12 −0
Original line number Diff line number Diff line
@@ -303,6 +303,18 @@ else
KBUILD_IMAGE := $(boot)/zImage
endif

ifeq ($(CONFIG_STACKPROTECTOR_PER_TASK),y)
prepare: stack_protector_prepare
stack_protector_prepare: prepare0
	$(eval KBUILD_CFLAGS += \
		-fplugin-arg-arm_ssp_per_task_plugin-tso=$(shell	\
			awk '{if ($$2 == "THREAD_SZ_ORDER") print $$3;}'\
				include/generated/asm-offsets.h)	\
		-fplugin-arg-arm_ssp_per_task_plugin-offset=$(shell	\
			awk '{if ($$2 == "TI_STACK_CANARY") print $$3;}'\
				include/generated/asm-offsets.h))
endif

all:	$(notdir $(KBUILD_IMAGE))


+1 −0
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ clean-files += piggy_data lib1funcs.S ashldi3.S bswapsdi2.S \
		$(libfdt) $(libfdt_hdrs) hyp-stub.S

KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
KBUILD_CFLAGS += $(DISABLE_ARM_SSP_PER_TASK_PLUGIN)

ifeq ($(CONFIG_FUNCTION_TRACER),y)
ORIG_CFLAGS := $(KBUILD_CFLAGS)
+10 −2
Original line number Diff line number Diff line
@@ -6,8 +6,10 @@
 * the stack frame and verifying that it hasn't been overwritten when
 * returning from the function.  The pattern is called stack canary
 * and gcc expects it to be defined by a global variable called
 * "__stack_chk_guard" on ARM.  This unfortunately means that on SMP
 * we cannot have a different canary value per task.
 * "__stack_chk_guard" on ARM.  This prevents SMP systems from using a
 * different value for each task unless we enable a GCC plugin that
 * replaces these symbol references with references to each task's own
 * value.
 */

#ifndef _ASM_STACKPROTECTOR_H
@@ -16,6 +18,8 @@
#include <linux/random.h>
#include <linux/version.h>

#include <asm/thread_info.h>

extern unsigned long __stack_chk_guard;

/*
@@ -33,7 +37,11 @@ static __always_inline void boot_init_stack_canary(void)
	canary ^= LINUX_VERSION_CODE;

	current->stack_canary = canary;
#ifndef CONFIG_STACKPROTECTOR_PER_TASK
	__stack_chk_guard = current->stack_canary;
#else
	current_thread_info()->stack_canary = current->stack_canary;
#endif
}

#endif	/* _ASM_STACKPROTECTOR_H */
+3 −0
Original line number Diff line number Diff line
@@ -53,6 +53,9 @@ struct thread_info {
	struct task_struct	*task;		/* main task structure */
	__u32			cpu;		/* cpu */
	__u32			cpu_domain;	/* cpu domain */
#ifdef CONFIG_STACKPROTECTOR_PER_TASK
	unsigned long		stack_canary;
#endif
	struct cpu_context_save	cpu_context;	/* cpu context */
	__u32			syscall;	/* syscall number */
	__u8			used_cp[16];	/* thread used copro */
Loading