Implements basic stack protector support based on ARM version in c743f38013aeff58ef6252601e397b5ba281c633 , with Kconfig option, constant canary value set at boot time, and script to check if compiler actually supports stack protector. Tested by creating a kernel module that writes past end of char[]. Signed-off-by: Gregory Fong <gregory.0xf0@xxxxxxxxx> --- arch/mips/Kconfig | 13 +++++++++++ arch/mips/Makefile | 4 ++++ arch/mips/include/asm/stackprotector.h | 40 ++++++++++++++++++++++++++++++++ arch/mips/kernel/process.c | 6 +++++ 4 files changed, 63 insertions(+) create mode 100644 arch/mips/include/asm/stackprotector.h diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 7a58ab9..a241588 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2381,6 +2381,19 @@ config SECCOMP If unsure, say Y. Only embedded should say N here. +config CC_STACKPROTECTOR + bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)" + help + This option turns on the -fstack-protector GCC feature. This + feature puts, at the beginning of functions, a canary value on + the stack just before the return address, and validates + the value just before actually returning. Stack based buffer + overflows (that need to overwrite this return address) now also + overwrite the canary, which gets detected and the attack is then + neutralized via a kernel panic. + + This feature requires gcc version 4.2 or above. + config USE_OF bool select OF diff --git a/arch/mips/Makefile b/arch/mips/Makefile index dd58a04..37f9ef3 100644 --- a/arch/mips/Makefile +++ b/arch/mips/Makefile @@ -227,6 +227,10 @@ KBUILD_CPPFLAGS += -DDATAOFFSET=$(if $(dataoffset-y),$(dataoffset-y),0) LDFLAGS += -m $(ld-emul) +ifdef CONFIG_CC_STACKPROTECTOR + KBUILD_CFLAGS += -fstack-protector +endif + ifdef CONFIG_MIPS CHECKFLAGS += $(shell $(CC) $(KBUILD_CFLAGS) -dM -E -x c /dev/null | \ egrep -vw '__GNUC_(|MINOR_|PATCHLEVEL_)_' | \ diff --git a/arch/mips/include/asm/stackprotector.h b/arch/mips/include/asm/stackprotector.h new file mode 100644 index 0000000..eb9b103 --- /dev/null +++ b/arch/mips/include/asm/stackprotector.h @@ -0,0 +1,40 @@ +/* + * GCC stack protector support. + * + * (This is directly adopted from the ARM implementation) + * + * Stack protector works by putting predefined pattern at the start of + * 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 MIPS. This unfortunately means that on SMP + * we cannot have a different canary value per task. + */ + +#ifndef _ASM_STACKPROTECTOR_H +#define _ASM_STACKPROTECTOR_H 1 + +#include <linux/random.h> +#include <linux/version.h> + +extern unsigned long __stack_chk_guard; + +/* + * 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. */ + get_random_bytes(&canary, sizeof(canary)); + canary ^= LINUX_VERSION_CODE; + + current->stack_canary = canary; + __stack_chk_guard = current->stack_canary; +} + +#endif /* _ASM_STACKPROTECTOR_H */ diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index c6a041d..7d62894 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -201,6 +201,12 @@ int dump_task_fpu(struct task_struct *t, elf_fpregset_t *fpr) return 1; } +#ifdef CONFIG_CC_STACKPROTECTOR +#include <linux/stackprotector.h> +unsigned long __stack_chk_guard __read_mostly; +EXPORT_SYMBOL(__stack_chk_guard); +#endif + /* * */ -- 1.7.9.5