arm64: enable per-task stack canaries
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Wed, 12 Dec 2018 12:08:44 +0000 (13:08 +0100)
committerWill Deacon <will.deacon@arm.com>
Wed, 12 Dec 2018 18:45:31 +0000 (18:45 +0000)
This enables the use of per-task stack canary values if GCC has
support for emitting the stack canary reference relative to the
value of sp_el0, which holds the task struct pointer in the arm64
kernel.

The $(eval) extends KBUILD_CFLAGS at the moment the make rule is
applied, which means asm-offsets.o (which we rely on for the offset
value) is built without the arguments, and everything built afterwards
has the options set.

Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
arch/arm64/Kconfig
arch/arm64/Makefile
arch/arm64/include/asm/stackprotector.h
arch/arm64/kernel/asm-offsets.c
arch/arm64/kernel/process.c

index e9af113..0b3aa2a 100644 (file)
@@ -1344,6 +1344,13 @@ config RANDOMIZE_MODULE_REGION_FULL
          a limited range that contains the [_stext, _etext] interval of the
          core kernel, so branch relocations are always in range.
 
+config CC_HAVE_STACKPROTECTOR_SYSREG
+       def_bool $(cc-option,-mstack-protector-guard=sysreg -mstack-protector-guard-reg=sp_el0 -mstack-protector-guard-offset=0)
+
+config STACKPROTECTOR_PER_TASK
+       def_bool y
+       depends on STACKPROTECTOR && CC_HAVE_STACKPROTECTOR_SYSREG
+
 endmenu
 
 menu "Boot options"
index 8978f60..398bdb8 100644 (file)
@@ -56,6 +56,16 @@ KBUILD_AFLAGS        += $(lseinstr) $(brokengasinst)
 KBUILD_CFLAGS  += $(call cc-option,-mabi=lp64)
 KBUILD_AFLAGS  += $(call cc-option,-mabi=lp64)
 
+ifeq ($(CONFIG_STACKPROTECTOR_PER_TASK),y)
+prepare: stack_protector_prepare
+stack_protector_prepare: prepare0
+       $(eval KBUILD_CFLAGS += -mstack-protector-guard=sysreg            \
+                               -mstack-protector-guard-reg=sp_el0        \
+                               -mstack-protector-guard-offset=$(shell    \
+                       awk '{if ($$2 == "TSK_STACK_CANARY") print $$3;}' \
+                                       include/generated/asm-offsets.h))
+endif
+
 ifeq ($(CONFIG_CPU_BIG_ENDIAN), y)
 KBUILD_CPPFLAGS        += -mbig-endian
 CHECKFLAGS     += -D__AARCH64EB__
index 58d15be..5884a2b 100644 (file)
@@ -34,7 +34,8 @@ static __always_inline void boot_init_stack_canary(void)
        canary &= CANARY_MASK;
 
        current->stack_canary = canary;
-       __stack_chk_guard = current->stack_canary;
+       if (!IS_ENABLED(CONFIG_STACKPROTECTOR_PER_TASK))
+               __stack_chk_guard = current->stack_canary;
 }
 
 #endif /* _ASM_STACKPROTECTOR_H */
index 323aeb5..65b8afc 100644 (file)
@@ -46,6 +46,9 @@ int main(void)
   DEFINE(TSK_TI_TTBR0,         offsetof(struct task_struct, thread_info.ttbr0));
 #endif
   DEFINE(TSK_STACK,            offsetof(struct task_struct, stack));
+#ifdef CONFIG_STACKPROTECTOR
+  DEFINE(TSK_STACK_CANARY,     offsetof(struct task_struct, stack_canary));
+#endif
   BLANK();
   DEFINE(THREAD_CPU_CONTEXT,   offsetof(struct task_struct, thread.cpu_context));
   BLANK();
index d9a4c2d..8a2d68f 100644 (file)
@@ -59,7 +59,7 @@
 #include <asm/processor.h>
 #include <asm/stacktrace.h>
 
-#ifdef CONFIG_STACKPROTECTOR
+#if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_STACKPROTECTOR_PER_TASK)
 #include <linux/stackprotector.h>
 unsigned long __stack_chk_guard __read_mostly;
 EXPORT_SYMBOL(__stack_chk_guard);