diff mbox series

[v3] arm64: enable per-task stack canaries

Message ID 20181212120844.19268-1-ard.biesheuvel@linaro.org
State Accepted
Commit 0a1213fa7432778b71a1c0166bf56660a3aab030
Headers show
Series [v3] arm64: enable per-task stack canaries | expand

Commit Message

Ard Biesheuvel Dec. 12, 2018, 12:08 p.m. UTC
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.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

---
v3: add all 3 options to the Kconfig cc-option check, to avoid relying on
    implementation defined logic in the compiler regarding which options
    need to appear together.

 arch/arm64/Kconfig                      |  7 +++++++
 arch/arm64/Makefile                     | 10 ++++++++++
 arch/arm64/include/asm/stackprotector.h |  3 ++-
 arch/arm64/kernel/asm-offsets.c         |  3 +++
 arch/arm64/kernel/process.c             |  2 +-
 5 files changed, 23 insertions(+), 2 deletions(-)

-- 
2.19.2

s

Comments

Kees Cook Dec. 12, 2018, 5:50 p.m. UTC | #1
On Wed, Dec 12, 2018 at 4:08 AM Ard Biesheuvel
<ard.biesheuvel@linaro.org> wrote:
>

> 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.

>

> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>


Reviewed-by: Kees Cook <keescook@chromium.org>


-Kees

> ---

> v3: add all 3 options to the Kconfig cc-option check, to avoid relying on

>     implementation defined logic in the compiler regarding which options

>     need to appear together.

>

>  arch/arm64/Kconfig                      |  7 +++++++

>  arch/arm64/Makefile                     | 10 ++++++++++

>  arch/arm64/include/asm/stackprotector.h |  3 ++-

>  arch/arm64/kernel/asm-offsets.c         |  3 +++

>  arch/arm64/kernel/process.c             |  2 +-

>  5 files changed, 23 insertions(+), 2 deletions(-)

>

> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig

> index ea2ab0330e3a..e355946cde97 100644

> --- a/arch/arm64/Kconfig

> +++ b/arch/arm64/Kconfig

> @@ -1272,6 +1272,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"

> diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile

> index 6cb9fc7e9382..79d927542322 100644

> --- a/arch/arm64/Makefile

> +++ b/arch/arm64/Makefile

> @@ -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__

> diff --git a/arch/arm64/include/asm/stackprotector.h b/arch/arm64/include/asm/stackprotector.h

> index 58d15be11c4d..5884a2b02827 100644

> --- a/arch/arm64/include/asm/stackprotector.h

> +++ b/arch/arm64/include/asm/stackprotector.h

> @@ -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 */

> diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c

> index 323aeb5f2fe6..65b8afc84466 100644

> --- a/arch/arm64/kernel/asm-offsets.c

> +++ b/arch/arm64/kernel/asm-offsets.c

> @@ -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();

> diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c

> index d9a4c2d6dd8b..8a2d68f04e0d 100644

> --- a/arch/arm64/kernel/process.c

> +++ b/arch/arm64/kernel/process.c

> @@ -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);

> --

> 2.19.2

>

> s




-- 
Kees Cook
Will Deacon Dec. 12, 2018, 7:28 p.m. UTC | #2
On Wed, Dec 12, 2018 at 09:50:37AM -0800, Kees Cook wrote:
> On Wed, Dec 12, 2018 at 4:08 AM Ard Biesheuvel

> <ard.biesheuvel@linaro.org> wrote:

> >

> > 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.

> >

> > Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

> 

> Reviewed-by: Kees Cook <keescook@chromium.org>


I've bitten the bullet and queued this for 4.21. We can always revert it
if the compiler support falls apart, but at this point the worst I can see
happening is that we have to change the name of an option.

Will
diff mbox series

Patch

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index ea2ab0330e3a..e355946cde97 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1272,6 +1272,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"
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index 6cb9fc7e9382..79d927542322 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -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__
diff --git a/arch/arm64/include/asm/stackprotector.h b/arch/arm64/include/asm/stackprotector.h
index 58d15be11c4d..5884a2b02827 100644
--- a/arch/arm64/include/asm/stackprotector.h
+++ b/arch/arm64/include/asm/stackprotector.h
@@ -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 */
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index 323aeb5f2fe6..65b8afc84466 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -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();
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index d9a4c2d6dd8b..8a2d68f04e0d 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -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);