diff options
-rw-r--r-- | arch/mips/Kconfig | 13 | ||||
-rw-r--r-- | arch/mips/Makefile | 4 | ||||
-rw-r--r-- | arch/mips/include/asm/stackprotector.h | 40 | ||||
-rw-r--r-- | arch/mips/kernel/process.c | 6 |
4 files changed, 63 insertions, 0 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 69bf31062ca4..6dbeb273afc6 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2367,6 +2367,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 dd58a04ef4bc..37f9ef324f2f 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 000000000000..eb9b1035e926 --- /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 c6a041d9d05d..7d62894f7e23 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 + /* * */ |