[PATCH 1/2] stackprotector: add stack smashing protector generic
From: Filippo ARCIDIACONO <hidden>
Date: 2010-12-23 13:45:45
Also in:
linux-arm-kernel, lkml
Subsystem:
arm port, generic include/asm header files, kernel build + files below scripts/ (unless maintained elsewhere), the rest, x86 architecture (32-bit and 64-bit) · Maintainers:
Russell King, Arnd Bergmann, Nathan Chancellor, Nicolas Schier, Linus Torvalds, Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen
The current implementation of SSP used for ARM architecture is based on the global variable __stack_chk_guard (see commit c743f38013aeff58ef6252601e397b5ba281c633 by Nicolas Pitre). This implementation should be generic enough to be used for all architectures that rely upon that global variable (i.e. SH), so the ARM code can be widely used for all those architectures. The kbuild uses a script to check if the architecture does actually need to define the __stack_chk_guard, so it will use the generic SSP code, otherwise it will fall back to the architecture specific one (i.e. x86, x86_64). Signed-off-by: Filippo Arcidiacono <redacted> Signed-off-by: Carmelo Amoroso <redacted> --- Makefile | 14 ++++++++- arch/Kconfig | 16 +++++++++++ arch/arm/Kconfig | 12 -------- arch/arm/Makefile | 4 --- arch/arm/include/asm/stackprotector.h | 38 --------------------------- arch/arm/kernel/process.c | 6 ---- arch/x86/Kconfig | 16 ----------- include/asm-generic/stackprotector.h | 39 ++++++++++++++++++++++++++++ include/linux/stackprotector.h | 6 +++- init/main.c | 5 +++ scripts/gcc-generic-has-stack-protector.sh | 9 ++++++ 11 files changed, 86 insertions(+), 79 deletions(-) delete mode 100644 arch/arm/include/asm/stackprotector.h create mode 100644 include/asm-generic/stackprotector.h create mode 100755 scripts/gcc-generic-has-stack-protector.sh
diff --git a/Makefile b/Makefile
index 77044b7..7530650 100644
--- a/Makefile
+++ b/Makefile@@ -550,8 +550,18 @@ KBUILD_CFLAGS += $(call cc-option,-Wframe-larger-than=${CONFIG_FRAME_WARN}) endif # Force gcc to behave correct even for buggy distributions -ifndef CONFIG_CC_STACKPROTECTOR -KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector) +ifdef CONFIG_CC_STACKPROTECTOR +stackp-y := $(call cc-option,-fstack-protector) +ifeq ($(stackp-y),) + $(warning stack protector enabled but no compiler support) +else +cc_has_sp := $(srctree)/scripts/gcc-generic-has-stack-protector.sh +ifeq ($(shell $(CONFIG_SHELL) $(cc_has_sp) $(CC)), y) + KBUILD_CFLAGS += $(stackp-y) -D__ARCH_WANT_STACK_CHK_GUARD +endif +endif +else + KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector) endif ifdef CONFIG_FRAME_POINTER
diff --git a/arch/Kconfig b/arch/Kconfig
index 8bf0fa6..083245d 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig@@ -175,4 +175,20 @@ config HAVE_PERF_EVENTS_NMI config HAVE_ARCH_JUMP_LABEL bool +config CC_STACKPROTECTOR + bool "Enable -fstack-protector buffer overflow detection" + 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, or a distribution + gcc with the feature backported. Older versions are automatically + detected and for those versions, this configuration option is + ignored. (and a warning is printed during bootup) + source "kernel/gcov/Kconfig"
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index d56d21c..58c29a5 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig@@ -1522,18 +1522,6 @@ config SECCOMP and the task is only allowed to execute a few safe syscalls defined by each seccomp mode. -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 DEPRECATED_PARAM_STRUCT bool "Provide old way to pass kernel parameters" help
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index b87aed0..ebbd003 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile@@ -37,10 +37,6 @@ ifeq ($(CONFIG_FRAME_POINTER),y) KBUILD_CFLAGS +=-fno-omit-frame-pointer -mapcs -mno-sched-prolog endif -ifeq ($(CONFIG_CC_STACKPROTECTOR),y) -KBUILD_CFLAGS +=-fstack-protector -endif - ifeq ($(CONFIG_CPU_BIG_ENDIAN),y) KBUILD_CPPFLAGS += -mbig-endian AS += -EB
diff --git a/arch/arm/include/asm/stackprotector.h b/arch/arm/include/asm/stackprotector.h
deleted file mode 100644
index de00332..0000000
--- a/arch/arm/include/asm/stackprotector.h
+++ /dev/null@@ -1,38 +0,0 @@ -/* - * GCC stack protector support. - * - * 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 ARM. 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/arm/kernel/process.c b/arch/arm/kernel/process.c
index e76fcaa..067b4de 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c@@ -39,12 +39,6 @@ #include <asm/stacktrace.h> #include <asm/mach/time.h> -#ifdef CONFIG_CC_STACKPROTECTOR -#include <linux/stackprotector.h> -unsigned long __stack_chk_guard __read_mostly; -EXPORT_SYMBOL(__stack_chk_guard); -#endif - static const char *processor_modes[] = { "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" , "UK4_26" , "UK5_26" , "UK6_26" , "UK7_26" , "UK8_26" , "UK9_26" , "UK10_26", "UK11_26", "UK12_26", "UK13_26", "UK14_26", "UK15_26",
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index e330da2..b8704dd 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig@@ -1455,22 +1455,6 @@ 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, or a distribution - gcc with the feature backported. Older versions are automatically - detected and for those versions, this configuration option is - ignored. (and a warning is printed during bootup) - source kernel/Kconfig.hz config KEXEC
diff --git a/include/asm-generic/stackprotector.h b/include/asm-generic/stackprotector.h
new file mode 100644
index 0000000..2cf9c65
--- /dev/null
+++ b/include/asm-generic/stackprotector.h@@ -0,0 +1,39 @@ +/* + * GCC stack protector support. + * (Generic implementation based on __stack_chk_guard) + * + * 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". This unfortunately means that on SMP + * we cannot have a different canary value per task. + */ + +#ifndef _LINUX_STACKPROTECTOR_H +#error "Never use <asm-generic/stackprotector.h> directly; \ +include <linux/stackprotector.h> instead." +#endif + +#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; +}
diff --git a/include/linux/stackprotector.h b/include/linux/stackprotector.h
index 6f3e54c..d71a437 100644
--- a/include/linux/stackprotector.h
+++ b/include/linux/stackprotector.h@@ -6,7 +6,11 @@ #include <linux/random.h> #ifdef CONFIG_CC_STACKPROTECTOR -# include <asm/stackprotector.h> +#ifdef __ARCH_WANT_STACK_CHK_GUARD +#include <asm-generic/stackprotector.h> +#else +#include <asm/stackprotector.h> +#endif #else static inline void boot_init_stack_canary(void) {
diff --git a/init/main.c b/init/main.c
index 8646401..8b2e070 100644
--- a/init/main.c
+++ b/init/main.c@@ -78,6 +78,11 @@ #include <asm/smp.h> #endif +#if defined CONFIG_CC_STACKPROTECTOR && defined __ARCH_WANT_STACK_CHK_GUARD +unsigned long __stack_chk_guard __read_mostly; +EXPORT_SYMBOL(__stack_chk_guard); +#endif + static int kernel_init(void *); extern void init_IRQ(void);
diff --git a/scripts/gcc-generic-has-stack-protector.sh b/scripts/gcc-generic-has-stack-protector.sh
new file mode 100755
index 0000000..11cc914
--- /dev/null
+++ b/scripts/gcc-generic-has-stack-protector.sh@@ -0,0 +1,9 @@ +#!/bin/sh + +echo "int foo(void) { char X[200]; return 3; }" | $1 -S -xc -c -O0 \ +-fstack-protector - -o - 2> /dev/null | grep -q __stack_chk_guard +if [ "$?" -eq "0" ] ; then + echo y +else + echo n +fi
--
1.5.5.6