提交 7890ba8c 编写于 作者: I Ingo Molnar

Merge branch 'stackprotector' into core/percpu

...@@ -1340,13 +1340,17 @@ config SECCOMP ...@@ -1340,13 +1340,17 @@ config SECCOMP
If unsure, say Y. Only embedded should say N here. If unsure, say Y. Only embedded should say N here.
config CC_STACKPROTECTOR_ALL
bool
config CC_STACKPROTECTOR config CC_STACKPROTECTOR
bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)" bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)"
depends on X86_64 && EXPERIMENTAL && BROKEN depends on X86_64
select CC_STACKPROTECTOR_ALL
help help
This option turns on the -fstack-protector GCC feature. This This option turns on the -fstack-protector GCC feature. This
feature puts, at the beginning of critical functions, a canary feature puts, at the beginning of functions, a canary value on
value on the stack just before the return address, and validates the stack just before the return address, and validates
the value just before actually returning. Stack based buffer the value just before actually returning. Stack based buffer
overflows (that need to overwrite this return address) now also overflows (that need to overwrite this return address) now also
overwrite the canary, which gets detected and the attack is then overwrite the canary, which gets detected and the attack is then
...@@ -1354,15 +1358,8 @@ config CC_STACKPROTECTOR ...@@ -1354,15 +1358,8 @@ config CC_STACKPROTECTOR
This feature requires gcc version 4.2 or above, or a distribution This feature requires gcc version 4.2 or above, or a distribution
gcc with the feature backported. Older versions are automatically gcc with the feature backported. Older versions are automatically
detected and for those versions, this configuration option is ignored. detected and for those versions, this configuration option is
ignored. (and a warning is printed during bootup)
config CC_STACKPROTECTOR_ALL
bool "Use stack-protector for all functions"
depends on CC_STACKPROTECTOR
help
Normally, GCC only inserts the canary value protection for
functions that use large-ish on-stack buffers. By enabling
this option, GCC will be asked to do this for ALL functions.
source kernel/Kconfig.hz source kernel/Kconfig.hz
......
...@@ -117,6 +117,7 @@ config DEBUG_RODATA ...@@ -117,6 +117,7 @@ config DEBUG_RODATA
config DEBUG_RODATA_TEST config DEBUG_RODATA_TEST
bool "Testcase for the DEBUG_RODATA feature" bool "Testcase for the DEBUG_RODATA feature"
depends on DEBUG_RODATA depends on DEBUG_RODATA
default y
help help
This option enables a testcase for the DEBUG_RODATA This option enables a testcase for the DEBUG_RODATA
feature as well as for the change_page_attr() infrastructure. feature as well as for the change_page_attr() infrastructure.
......
...@@ -73,7 +73,7 @@ else ...@@ -73,7 +73,7 @@ else
stackp := $(CONFIG_SHELL) $(srctree)/scripts/gcc-x86_64-has-stack-protector.sh stackp := $(CONFIG_SHELL) $(srctree)/scripts/gcc-x86_64-has-stack-protector.sh
stackp-$(CONFIG_CC_STACKPROTECTOR) := $(shell $(stackp) \ stackp-$(CONFIG_CC_STACKPROTECTOR) := $(shell $(stackp) \
"$(CC)" -fstack-protector ) "$(CC)" "-fstack-protector -DGCC_HAS_SP" )
stackp-$(CONFIG_CC_STACKPROTECTOR_ALL) += $(shell $(stackp) \ stackp-$(CONFIG_CC_STACKPROTECTOR_ALL) += $(shell $(stackp) \
"$(CC)" -fstack-protector-all ) "$(CC)" -fstack-protector-all )
......
...@@ -17,11 +17,9 @@ struct x8664_pda { ...@@ -17,11 +17,9 @@ struct x8664_pda {
unsigned long unused4; unsigned long unused4;
int unused5; int unused5;
unsigned int unused6; /* 36 was cpunumber */ unsigned int unused6; /* 36 was cpunumber */
#ifdef CONFIG_CC_STACKPROTECTOR
unsigned long stack_canary; /* 40 stack canary value */ unsigned long stack_canary; /* 40 stack canary value */
/* gcc-ABI: this canary MUST be at /* gcc-ABI: this canary MUST be at
offset 40!!! */ offset 40!!! */
#endif
short in_bootmem; /* pda lives in bootmem */ short in_bootmem; /* pda lives in bootmem */
} ____cacheline_aligned_in_smp; } ____cacheline_aligned_in_smp;
...@@ -42,4 +40,6 @@ extern void pda_init(int); ...@@ -42,4 +40,6 @@ extern void pda_init(int);
#endif #endif
#define refresh_stack_canary() write_pda(stack_canary, current->stack_canary)
#endif /* _ASM_X86_PDA_H */ #endif /* _ASM_X86_PDA_H */
#ifndef _ASM_STACKPROTECTOR_H
#define _ASM_STACKPROTECTOR_H 1
#include <asm/tsc.h>
#include <asm/pda.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)
{
u64 canary;
u64 tsc;
/*
* If we're the non-boot CPU, nothing set the PDA stack
* canary up for us - and if we are the boot CPU we have
* a 0 stack canary. This is a good place for updating
* it, as we wont ever return from this function (so the
* invalid canaries already on the stack wont ever
* trigger).
*
* We both use the random pool and the current TSC as a source
* of randomness. The TSC only matters for very early init,
* there it already has some randomness on most systems. Later
* on during the bootup the random pool has true entropy too.
*/
get_random_bytes(&canary, sizeof(canary));
tsc = __native_read_tsc();
canary += tsc + (tsc << 32UL);
current->stack_canary = canary;
write_pda(stack_canary, canary);
}
#endif
...@@ -95,6 +95,8 @@ do { \ ...@@ -95,6 +95,8 @@ do { \
".globl thread_return\n" \ ".globl thread_return\n" \
"thread_return:\n\t" \ "thread_return:\n\t" \
"movq "__percpu_arg([current_task])",%%rsi\n\t" \ "movq "__percpu_arg([current_task])",%%rsi\n\t" \
"movq %P[task_canary](%%rsi),%%r8\n\t" \
"movq %%r8,%%gs:%P[pda_canary]\n\t" \
"movq %P[thread_info](%%rsi),%%r8\n\t" \ "movq %P[thread_info](%%rsi),%%r8\n\t" \
LOCK_PREFIX "btr %[tif_fork],%P[ti_flags](%%r8)\n\t" \ LOCK_PREFIX "btr %[tif_fork],%P[ti_flags](%%r8)\n\t" \
"movq %%rax,%%rdi\n\t" \ "movq %%rax,%%rdi\n\t" \
...@@ -106,7 +108,9 @@ do { \ ...@@ -106,7 +108,9 @@ do { \
[ti_flags] "i" (offsetof(struct thread_info, flags)), \ [ti_flags] "i" (offsetof(struct thread_info, flags)), \
[tif_fork] "i" (TIF_FORK), \ [tif_fork] "i" (TIF_FORK), \
[thread_info] "i" (offsetof(struct task_struct, stack)), \ [thread_info] "i" (offsetof(struct task_struct, stack)), \
[current_task] "m" (per_cpu_var(current_task)) \ [task_canary] "i" (offsetof(struct task_struct, stack_canary)),\
[current_task] "m" (per_cpu_var(current_task)), \
[pda_canary] "i" (offsetof(struct x8664_pda, stack_canary))\
: "memory", "cc" __EXTRA_CLOBBER) : "memory", "cc" __EXTRA_CLOBBER)
#endif #endif
......
...@@ -23,6 +23,7 @@ nostackp := $(call cc-option, -fno-stack-protector) ...@@ -23,6 +23,7 @@ nostackp := $(call cc-option, -fno-stack-protector)
CFLAGS_vsyscall_64.o := $(PROFILING) -g0 $(nostackp) CFLAGS_vsyscall_64.o := $(PROFILING) -g0 $(nostackp)
CFLAGS_hpet.o := $(nostackp) CFLAGS_hpet.o := $(nostackp)
CFLAGS_tsc.o := $(nostackp) CFLAGS_tsc.o := $(nostackp)
CFLAGS_paravirt.o := $(nostackp)
obj-y := process_$(BITS).o signal.o entry_$(BITS).o obj-y := process_$(BITS).o signal.o entry_$(BITS).o
obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <linux/stackprotector.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/sched.h> #include <linux/sched.h>
...@@ -117,6 +118,17 @@ static inline void play_dead(void) ...@@ -117,6 +118,17 @@ static inline void play_dead(void)
void cpu_idle(void) void cpu_idle(void)
{ {
current_thread_info()->status |= TS_POLLING; current_thread_info()->status |= TS_POLLING;
/*
* If we're the non-boot CPU, nothing set the PDA stack
* canary up for us - and if we are the boot CPU we have
* a 0 stack canary. This is a good place for updating
* it, as we wont ever return from this function (so the
* invalid canaries already on the stack wont ever
* trigger):
*/
boot_init_stack_canary();
/* endless idle loop with no priority at all */ /* endless idle loop with no priority at all */
while (1) { while (1) {
tick_nohz_stop_sched_tick(1); tick_nohz_stop_sched_tick(1);
...@@ -627,7 +639,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) ...@@ -627,7 +639,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
(unsigned long)task_stack_page(next_p) + (unsigned long)task_stack_page(next_p) +
THREAD_SIZE - KERNEL_STACK_OFFSET); THREAD_SIZE - KERNEL_STACK_OFFSET);
#ifdef CONFIG_CC_STACKPROTECTOR #ifdef CONFIG_CC_STACKPROTECTOR
write_pda(stack_canary, next_p->stack_canary);
/* /*
* Build time only check to make sure the stack_canary is at * Build time only check to make sure the stack_canary is at
* offset 40 in the pda; this is a gcc ABI requirement * offset 40 in the pda; this is a gcc ABI requirement
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/kprobes.h> #include <linux/kprobes.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/kdebug.h> #include <linux/kdebug.h>
#include <linux/magic.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/desc.h> #include <asm/desc.h>
...@@ -589,6 +590,8 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code) ...@@ -589,6 +590,8 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
unsigned long address; unsigned long address;
int write, si_code; int write, si_code;
int fault; int fault;
unsigned long *stackend;
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
unsigned long flags; unsigned long flags;
int sig; int sig;
...@@ -841,6 +844,10 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code) ...@@ -841,6 +844,10 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
show_fault_oops(regs, error_code, address); show_fault_oops(regs, error_code, address);
stackend = end_of_stack(tsk);
if (*stackend != STACK_END_MAGIC)
printk(KERN_ALERT "Thread overran stack, or stack corrupted\n");
tsk->thread.cr2 = address; tsk->thread.cr2 = address;
tsk->thread.trap_no = 14; tsk->thread.trap_no = 14;
tsk->thread.error_code = error_code; tsk->thread.error_code = error_code;
......
...@@ -47,4 +47,5 @@ ...@@ -47,4 +47,5 @@
#define FUTEXFS_SUPER_MAGIC 0xBAD1DEA #define FUTEXFS_SUPER_MAGIC 0xBAD1DEA
#define INOTIFYFS_SUPER_MAGIC 0x2BAD1DEA #define INOTIFYFS_SUPER_MAGIC 0x2BAD1DEA
#define STACK_END_MAGIC 0x57AC6E9D
#endif /* __LINUX_MAGIC_H__ */ #endif /* __LINUX_MAGIC_H__ */
...@@ -1157,10 +1157,9 @@ struct task_struct { ...@@ -1157,10 +1157,9 @@ struct task_struct {
pid_t pid; pid_t pid;
pid_t tgid; pid_t tgid;
#ifdef CONFIG_CC_STACKPROTECTOR
/* Canary value for the -fstack-protector gcc feature */ /* Canary value for the -fstack-protector gcc feature */
unsigned long stack_canary; unsigned long stack_canary;
#endif
/* /*
* pointers to (original) parent process, youngest child, younger sibling, * pointers to (original) parent process, youngest child, younger sibling,
* older sibling, respectively. (p->father can be replaced with * older sibling, respectively. (p->father can be replaced with
...@@ -2066,6 +2065,19 @@ static inline int object_is_on_stack(void *obj) ...@@ -2066,6 +2065,19 @@ static inline int object_is_on_stack(void *obj)
extern void thread_info_cache_init(void); extern void thread_info_cache_init(void);
#ifdef CONFIG_DEBUG_STACK_USAGE
static inline unsigned long stack_not_used(struct task_struct *p)
{
unsigned long *n = end_of_stack(p);
do { /* Skip over canary */
n++;
} while (!*n);
return (unsigned long)n - (unsigned long)end_of_stack(p);
}
#endif
/* set thread flags in other task's structures /* set thread flags in other task's structures
* - see asm/thread_info.h for TIF_xxxx flags available * - see asm/thread_info.h for TIF_xxxx flags available
*/ */
......
#ifndef _LINUX_STACKPROTECTOR_H
#define _LINUX_STACKPROTECTOR_H 1
#include <linux/compiler.h>
#include <linux/sched.h>
#include <linux/random.h>
#ifdef CONFIG_CC_STACKPROTECTOR
# include <asm/stackprotector.h>
#else
static inline void boot_init_stack_canary(void)
{
}
#endif
#endif
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <linux/stackprotector.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -539,6 +540,12 @@ asmlinkage void __init start_kernel(void) ...@@ -539,6 +540,12 @@ asmlinkage void __init start_kernel(void)
*/ */
lockdep_init(); lockdep_init();
debug_objects_early_init(); debug_objects_early_init();
/*
* Set up the the initial canary ASAP:
*/
boot_init_stack_canary();
cgroup_init_early(); cgroup_init_early();
local_irq_disable(); local_irq_disable();
......
...@@ -977,12 +977,9 @@ static void check_stack_usage(void) ...@@ -977,12 +977,9 @@ static void check_stack_usage(void)
{ {
static DEFINE_SPINLOCK(low_water_lock); static DEFINE_SPINLOCK(low_water_lock);
static int lowest_to_date = THREAD_SIZE; static int lowest_to_date = THREAD_SIZE;
unsigned long *n = end_of_stack(current);
unsigned long free; unsigned long free;
while (*n == 0) free = stack_not_used(current);
n++;
free = (unsigned long)n - (unsigned long)end_of_stack(current);
if (free >= lowest_to_date) if (free >= lowest_to_date)
return; return;
......
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <trace/sched.h> #include <trace/sched.h>
#include <linux/magic.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
...@@ -212,6 +213,8 @@ static struct task_struct *dup_task_struct(struct task_struct *orig) ...@@ -212,6 +213,8 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
{ {
struct task_struct *tsk; struct task_struct *tsk;
struct thread_info *ti; struct thread_info *ti;
unsigned long *stackend;
int err; int err;
prepare_to_copy(orig); prepare_to_copy(orig);
...@@ -237,6 +240,8 @@ static struct task_struct *dup_task_struct(struct task_struct *orig) ...@@ -237,6 +240,8 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
goto out; goto out;
setup_thread_stack(tsk, orig); setup_thread_stack(tsk, orig);
stackend = end_of_stack(tsk);
*stackend = STACK_END_MAGIC; /* for overflow detection */
#ifdef CONFIG_CC_STACKPROTECTOR #ifdef CONFIG_CC_STACKPROTECTOR
tsk->stack_canary = get_random_int(); tsk->stack_canary = get_random_int();
......
...@@ -74,6 +74,9 @@ NORET_TYPE void panic(const char * fmt, ...) ...@@ -74,6 +74,9 @@ NORET_TYPE void panic(const char * fmt, ...)
vsnprintf(buf, sizeof(buf), fmt, args); vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args); va_end(args);
printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf); printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf);
#ifdef CONFIG_DEBUG_BUGVERBOSE
dump_stack();
#endif
bust_spinlocks(0); bust_spinlocks(0);
/* /*
...@@ -355,15 +358,22 @@ EXPORT_SYMBOL(warn_slowpath); ...@@ -355,15 +358,22 @@ EXPORT_SYMBOL(warn_slowpath);
#endif #endif
#ifdef CONFIG_CC_STACKPROTECTOR #ifdef CONFIG_CC_STACKPROTECTOR
#ifndef GCC_HAS_SP
#warning You have selected the CONFIG_CC_STACKPROTECTOR option, but the gcc used does not support this.
#endif
/* /*
* Called when gcc's -fstack-protector feature is used, and * Called when gcc's -fstack-protector feature is used, and
* gcc detects corruption of the on-stack canary value * gcc detects corruption of the on-stack canary value
*/ */
void __stack_chk_fail(void) void __stack_chk_fail(void)
{ {
panic("stack-protector: Kernel stack is corrupted"); panic("stack-protector: Kernel stack is corrupted in: %p\n",
__builtin_return_address(0));
} }
EXPORT_SYMBOL(__stack_chk_fail); EXPORT_SYMBOL(__stack_chk_fail);
#endif #endif
core_param(panic, panic_timeout, int, 0644); core_param(panic, panic_timeout, int, 0644);
......
...@@ -5939,12 +5939,7 @@ void sched_show_task(struct task_struct *p) ...@@ -5939,12 +5939,7 @@ void sched_show_task(struct task_struct *p)
printk(KERN_CONT " %016lx ", thread_saved_pc(p)); printk(KERN_CONT " %016lx ", thread_saved_pc(p));
#endif #endif
#ifdef CONFIG_DEBUG_STACK_USAGE #ifdef CONFIG_DEBUG_STACK_USAGE
{ free = stack_not_used(p);
unsigned long *n = end_of_stack(p);
while (!*n)
n++;
free = (unsigned long)n - (unsigned long)end_of_stack(p);
}
#endif #endif
printk(KERN_CONT "%5lu %5d %6d\n", free, printk(KERN_CONT "%5lu %5d %6d\n", free,
task_pid_nr(p), task_pid_nr(p->real_parent)); task_pid_nr(p), task_pid_nr(p->real_parent));
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册