Merge branch 'stackprotector' into core/percpu
This commit is contained in:
commit
7890ba8c87
17 changed files with 134 additions and 31 deletions
|
@ -1340,13 +1340,17 @@ config SECCOMP
|
|||
|
||||
If unsure, say Y. Only embedded should say N here.
|
||||
|
||||
config CC_STACKPROTECTOR_ALL
|
||||
bool
|
||||
|
||||
config CC_STACKPROTECTOR
|
||||
bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)"
|
||||
depends on X86_64 && EXPERIMENTAL && BROKEN
|
||||
depends on X86_64
|
||||
select CC_STACKPROTECTOR_ALL
|
||||
help
|
||||
This option turns on the -fstack-protector GCC feature. This
|
||||
feature puts, at the beginning of critical functions, a canary
|
||||
value on the stack just before the return address, and validates
|
||||
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
|
||||
|
@ -1354,15 +1358,8 @@ config CC_STACKPROTECTOR
|
|||
|
||||
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.
|
||||
|
||||
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.
|
||||
detected and for those versions, this configuration option is
|
||||
ignored. (and a warning is printed during bootup)
|
||||
|
||||
source kernel/Kconfig.hz
|
||||
|
||||
|
|
|
@ -117,6 +117,7 @@ config DEBUG_RODATA
|
|||
config DEBUG_RODATA_TEST
|
||||
bool "Testcase for the DEBUG_RODATA feature"
|
||||
depends on DEBUG_RODATA
|
||||
default y
|
||||
help
|
||||
This option enables a testcase for the DEBUG_RODATA
|
||||
feature as well as for the change_page_attr() infrastructure.
|
||||
|
|
|
@ -73,7 +73,7 @@ else
|
|||
|
||||
stackp := $(CONFIG_SHELL) $(srctree)/scripts/gcc-x86_64-has-stack-protector.sh
|
||||
stackp-$(CONFIG_CC_STACKPROTECTOR) := $(shell $(stackp) \
|
||||
"$(CC)" -fstack-protector )
|
||||
"$(CC)" "-fstack-protector -DGCC_HAS_SP" )
|
||||
stackp-$(CONFIG_CC_STACKPROTECTOR_ALL) += $(shell $(stackp) \
|
||||
"$(CC)" -fstack-protector-all )
|
||||
|
||||
|
|
|
@ -17,11 +17,9 @@ struct x8664_pda {
|
|||
unsigned long unused4;
|
||||
int unused5;
|
||||
unsigned int unused6; /* 36 was cpunumber */
|
||||
#ifdef CONFIG_CC_STACKPROTECTOR
|
||||
unsigned long stack_canary; /* 40 stack canary value */
|
||||
/* gcc-ABI: this canary MUST be at
|
||||
offset 40!!! */
|
||||
#endif
|
||||
short in_bootmem; /* pda lives in bootmem */
|
||||
} ____cacheline_aligned_in_smp;
|
||||
|
||||
|
@ -42,4 +40,6 @@ extern void pda_init(int);
|
|||
|
||||
#endif
|
||||
|
||||
#define refresh_stack_canary() write_pda(stack_canary, current->stack_canary)
|
||||
|
||||
#endif /* _ASM_X86_PDA_H */
|
||||
|
|
39
arch/x86/include/asm/stackprotector.h
Normal file
39
arch/x86/include/asm/stackprotector.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
#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 { \
|
|||
".globl thread_return\n" \
|
||||
"thread_return:\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" \
|
||||
LOCK_PREFIX "btr %[tif_fork],%P[ti_flags](%%r8)\n\t" \
|
||||
"movq %%rax,%%rdi\n\t" \
|
||||
|
@ -106,7 +108,9 @@ do { \
|
|||
[ti_flags] "i" (offsetof(struct thread_info, flags)), \
|
||||
[tif_fork] "i" (TIF_FORK), \
|
||||
[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)
|
||||
#endif
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ nostackp := $(call cc-option, -fno-stack-protector)
|
|||
CFLAGS_vsyscall_64.o := $(PROFILING) -g0 $(nostackp)
|
||||
CFLAGS_hpet.o := $(nostackp)
|
||||
CFLAGS_tsc.o := $(nostackp)
|
||||
CFLAGS_paravirt.o := $(nostackp)
|
||||
|
||||
obj-y := process_$(BITS).o signal.o entry_$(BITS).o
|
||||
obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <linux/stackprotector.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sched.h>
|
||||
|
@ -117,6 +118,17 @@ static inline void play_dead(void)
|
|||
void cpu_idle(void)
|
||||
{
|
||||
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 */
|
||||
while (1) {
|
||||
tick_nohz_stop_sched_tick(1);
|
||||
|
@ -627,7 +639,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
|
|||
(unsigned long)task_stack_page(next_p) +
|
||||
THREAD_SIZE - KERNEL_STACK_OFFSET);
|
||||
#ifdef CONFIG_CC_STACKPROTECTOR
|
||||
write_pda(stack_canary, next_p->stack_canary);
|
||||
/*
|
||||
* Build time only check to make sure the stack_canary is at
|
||||
* offset 40 in the pda; this is a gcc ABI requirement
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/kprobes.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/kdebug.h>
|
||||
#include <linux/magic.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/desc.h>
|
||||
|
@ -589,6 +590,8 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
|
|||
unsigned long address;
|
||||
int write, si_code;
|
||||
int fault;
|
||||
unsigned long *stackend;
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
unsigned long flags;
|
||||
int sig;
|
||||
|
@ -841,6 +844,10 @@ no_context:
|
|||
|
||||
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.trap_no = 14;
|
||||
tsk->thread.error_code = error_code;
|
||||
|
|
|
@ -47,4 +47,5 @@
|
|||
#define FUTEXFS_SUPER_MAGIC 0xBAD1DEA
|
||||
#define INOTIFYFS_SUPER_MAGIC 0x2BAD1DEA
|
||||
|
||||
#define STACK_END_MAGIC 0x57AC6E9D
|
||||
#endif /* __LINUX_MAGIC_H__ */
|
||||
|
|
|
@ -1157,10 +1157,9 @@ struct task_struct {
|
|||
pid_t pid;
|
||||
pid_t tgid;
|
||||
|
||||
#ifdef CONFIG_CC_STACKPROTECTOR
|
||||
/* Canary value for the -fstack-protector gcc feature */
|
||||
unsigned long stack_canary;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* pointers to (original) parent process, youngest child, younger sibling,
|
||||
* older sibling, respectively. (p->father can be replaced with
|
||||
|
@ -2066,6 +2065,19 @@ static inline int object_is_on_stack(void *obj)
|
|||
|
||||
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
|
||||
* - see asm/thread_info.h for TIF_xxxx flags available
|
||||
*/
|
||||
|
|
16
include/linux/stackprotector.h
Normal file
16
include/linux/stackprotector.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
#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 @@
|
|||
#include <linux/proc_fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/stackprotector.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/delay.h>
|
||||
|
@ -539,6 +540,12 @@ asmlinkage void __init start_kernel(void)
|
|||
*/
|
||||
lockdep_init();
|
||||
debug_objects_early_init();
|
||||
|
||||
/*
|
||||
* Set up the the initial canary ASAP:
|
||||
*/
|
||||
boot_init_stack_canary();
|
||||
|
||||
cgroup_init_early();
|
||||
|
||||
local_irq_disable();
|
||||
|
|
|
@ -977,12 +977,9 @@ static void check_stack_usage(void)
|
|||
{
|
||||
static DEFINE_SPINLOCK(low_water_lock);
|
||||
static int lowest_to_date = THREAD_SIZE;
|
||||
unsigned long *n = end_of_stack(current);
|
||||
unsigned long free;
|
||||
|
||||
while (*n == 0)
|
||||
n++;
|
||||
free = (unsigned long)n - (unsigned long)end_of_stack(current);
|
||||
free = stack_not_used(current);
|
||||
|
||||
if (free >= lowest_to_date)
|
||||
return;
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#include <linux/proc_fs.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <trace/sched.h>
|
||||
#include <linux/magic.h>
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/pgalloc.h>
|
||||
|
@ -212,6 +213,8 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
|
|||
{
|
||||
struct task_struct *tsk;
|
||||
struct thread_info *ti;
|
||||
unsigned long *stackend;
|
||||
|
||||
int err;
|
||||
|
||||
prepare_to_copy(orig);
|
||||
|
@ -237,6 +240,8 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
|
|||
goto out;
|
||||
|
||||
setup_thread_stack(tsk, orig);
|
||||
stackend = end_of_stack(tsk);
|
||||
*stackend = STACK_END_MAGIC; /* for overflow detection */
|
||||
|
||||
#ifdef CONFIG_CC_STACKPROTECTOR
|
||||
tsk->stack_canary = get_random_int();
|
||||
|
|
|
@ -74,6 +74,9 @@ NORET_TYPE void panic(const char * fmt, ...)
|
|||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
va_end(args);
|
||||
printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf);
|
||||
#ifdef CONFIG_DEBUG_BUGVERBOSE
|
||||
dump_stack();
|
||||
#endif
|
||||
bust_spinlocks(0);
|
||||
|
||||
/*
|
||||
|
@ -355,15 +358,22 @@ EXPORT_SYMBOL(warn_slowpath);
|
|||
#endif
|
||||
|
||||
#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
|
||||
* gcc detects corruption of the on-stack canary value
|
||||
*/
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
||||
core_param(panic, panic_timeout, int, 0644);
|
||||
|
|
|
@ -5939,12 +5939,7 @@ void sched_show_task(struct task_struct *p)
|
|||
printk(KERN_CONT " %016lx ", thread_saved_pc(p));
|
||||
#endif
|
||||
#ifdef CONFIG_DEBUG_STACK_USAGE
|
||||
{
|
||||
unsigned long *n = end_of_stack(p);
|
||||
while (!*n)
|
||||
n++;
|
||||
free = (unsigned long)n - (unsigned long)end_of_stack(p);
|
||||
}
|
||||
free = stack_not_used(p);
|
||||
#endif
|
||||
printk(KERN_CONT "%5lu %5d %6d\n", free,
|
||||
task_pid_nr(p), task_pid_nr(p->real_parent));
|
||||
|
|
Reference in a new issue