Commit c3ff2a51 authored by Christophe Leroy's avatar Christophe Leroy Committed by Michael Ellerman

powerpc/32: add stack protector support

This functionality was tentatively added in the past
(commit 6533b7c1 ("powerpc: Initial stack protector
(-fstack-protector) support")) but had to be reverted
(commit f2574030 ("powerpc: Revert the initial stack
protector support") because of GCC implementing it differently
whether it had been built with libc support or not.

Now, GCC offers the possibility to manually set the
stack-protector mode (global or tls) regardless of libc support.

This time, the patch selects HAVE_STACKPROTECTOR only if
-mstack-protector-guard=tls is supported by GCC.

On PPC32, as register r2 points to current task_struct at
all time, the stack_canary located inside task_struct can be
used directly by using the following GCC options:
-mstack-protector-guard=tls
-mstack-protector-guard-reg=r2
-mstack-protector-guard-offset=offsetof(struct task_struct, stack_canary))

The protector is disabled for prom_init and bootx_init as
it is too early to handle it properly.

 $ echo CORRUPT_STACK > /sys/kernel/debug/provoke-crash/DIRECT
[  134.943666] Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: lkdtm_CORRUPT_STACK+0x64/0x64
[  134.943666]
[  134.955414] CPU: 0 PID: 283 Comm: sh Not tainted 4.18.0-s3k-dev-12143-ga3272be41209 #835
[  134.963380] Call Trace:
[  134.965860] [c6615d60] [c001f76c] panic+0x118/0x260 (unreliable)
[  134.971775] [c6615dc0] [c001f654] panic+0x0/0x260
[  134.976435] [c6615dd0] [c032c368] lkdtm_CORRUPT_STACK_STRONG+0x0/0x64
[  134.982769] [c6615e00] [ffffffff] 0xffffffff
Signed-off-by: default avatarChristophe Leroy <christophe.leroy@c-s.fr>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent cd5ff945
...@@ -180,6 +180,7 @@ config PPC ...@@ -180,6 +180,7 @@ config PPC
select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_TRACEHOOK select HAVE_ARCH_TRACEHOOK
select HAVE_CBPF_JIT if !PPC64 select HAVE_CBPF_JIT if !PPC64
select HAVE_STACKPROTECTOR if $(cc-option,-mstack-protector-guard=tls) && PPC32
select HAVE_CONTEXT_TRACKING if PPC64 select HAVE_CONTEXT_TRACKING if PPC64
select HAVE_DEBUG_KMEMLEAK select HAVE_DEBUG_KMEMLEAK
select HAVE_DEBUG_STACKOVERFLOW select HAVE_DEBUG_STACKOVERFLOW
......
...@@ -112,6 +112,9 @@ KBUILD_LDFLAGS += -m elf$(BITS)$(LDEMULATION) ...@@ -112,6 +112,9 @@ KBUILD_LDFLAGS += -m elf$(BITS)$(LDEMULATION)
KBUILD_ARFLAGS += --target=elf$(BITS)-$(GNUTARGET) KBUILD_ARFLAGS += --target=elf$(BITS)-$(GNUTARGET)
endif endif
cflags-$(CONFIG_STACKPROTECTOR) += -mstack-protector-guard=tls
cflags-$(CONFIG_STACKPROTECTOR) += -mstack-protector-guard-reg=r2
LDFLAGS_vmlinux-y := -Bstatic LDFLAGS_vmlinux-y := -Bstatic
LDFLAGS_vmlinux-$(CONFIG_RELOCATABLE) := -pie LDFLAGS_vmlinux-$(CONFIG_RELOCATABLE) := -pie
LDFLAGS_vmlinux := $(LDFLAGS_vmlinux-y) LDFLAGS_vmlinux := $(LDFLAGS_vmlinux-y)
...@@ -404,6 +407,13 @@ archclean: ...@@ -404,6 +407,13 @@ archclean:
archprepare: checkbin archprepare: checkbin
ifdef CONFIG_STACKPROTECTOR
prepare: stack_protector_prepare
stack_protector_prepare: prepare0
$(eval KBUILD_CFLAGS += -mstack-protector-guard-offset=$(shell awk '{if ($$2 == "TASK_CANARY") print $$3;}' include/generated/asm-offsets.h))
endif
# Use the file '.tmp_gas_check' for binutils tests, as gas won't output # Use the file '.tmp_gas_check' for binutils tests, as gas won't output
# to stdout and these checks are run even on install targets. # to stdout and these checks are run even on install targets.
TOUT := .tmp_gas_check TOUT := .tmp_gas_check
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* GCC stack protector support.
*
*/
#ifndef _ASM_STACKPROTECTOR_H
#define _ASM_STACKPROTECTOR_H
#include <linux/random.h>
#include <linux/version.h>
#include <asm/reg.h>
#include <asm/current.h>
/*
* Initialize the stackprotector canary value.
*
* NOTE: this must only be called from functions that never return,
* and it must always be inlined.
*/
static __always_inline void boot_init_stack_canary(void)
{
unsigned long canary;
/* Try to get a semi random initial value. */
canary = get_random_canary();
canary ^= mftb();
canary ^= LINUX_VERSION_CODE;
canary &= CANARY_MASK;
current->stack_canary = canary;
}
#endif /* _ASM_STACKPROTECTOR_H */
...@@ -20,6 +20,8 @@ CFLAGS_prom_init.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) ...@@ -20,6 +20,8 @@ CFLAGS_prom_init.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
CFLAGS_btext.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) CFLAGS_btext.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
CFLAGS_prom.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) CFLAGS_prom.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
CFLAGS_prom_init.o += $(call cc-option, -fno-stack-protector)
ifdef CONFIG_FUNCTION_TRACER ifdef CONFIG_FUNCTION_TRACER
# Do not trace early boot code # Do not trace early boot code
CFLAGS_REMOVE_cputable.o = $(CC_FLAGS_FTRACE) CFLAGS_REMOVE_cputable.o = $(CC_FLAGS_FTRACE)
......
...@@ -79,6 +79,9 @@ int main(void) ...@@ -79,6 +79,9 @@ int main(void)
{ {
OFFSET(THREAD, task_struct, thread); OFFSET(THREAD, task_struct, thread);
OFFSET(MM, task_struct, mm); OFFSET(MM, task_struct, mm);
#ifdef CONFIG_STACKPROTECTOR
OFFSET(TASK_CANARY, task_struct, stack_canary);
#endif
OFFSET(MMCONTEXTID, mm_struct, context.id); OFFSET(MMCONTEXTID, mm_struct, context.id);
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
DEFINE(SIGSEGV, SIGSEGV); DEFINE(SIGSEGV, SIGSEGV);
......
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
CFLAGS_bootx_init.o += -fPIC CFLAGS_bootx_init.o += -fPIC
CFLAGS_bootx_init.o += $(call cc-option, -fno-stack-protector)
ifdef CONFIG_FUNCTION_TRACER ifdef CONFIG_FUNCTION_TRACER
# Do not trace early boot code # Do not trace early boot code
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment