diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/fork.c | 5 | ||||
-rw-r--r-- | kernel/lockdep.c | 9 | ||||
-rw-r--r-- | kernel/panic.c | 13 | ||||
-rw-r--r-- | kernel/spinlock.c | 5 | ||||
-rw-r--r-- | kernel/sys.c | 31 | ||||
-rw-r--r-- | kernel/sysctl.c | 23 | ||||
-rw-r--r-- | kernel/unwind.c | 35 |
7 files changed, 110 insertions, 11 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index f9b014e3e700..a0dad84567c9 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <linux/cn_proc.h> | 45 | #include <linux/cn_proc.h> |
46 | #include <linux/delayacct.h> | 46 | #include <linux/delayacct.h> |
47 | #include <linux/taskstats_kern.h> | 47 | #include <linux/taskstats_kern.h> |
48 | #include <linux/random.h> | ||
48 | 49 | ||
49 | #include <asm/pgtable.h> | 50 | #include <asm/pgtable.h> |
50 | #include <asm/pgalloc.h> | 51 | #include <asm/pgalloc.h> |
@@ -175,6 +176,10 @@ static struct task_struct *dup_task_struct(struct task_struct *orig) | |||
175 | tsk->thread_info = ti; | 176 | tsk->thread_info = ti; |
176 | setup_thread_stack(tsk, orig); | 177 | setup_thread_stack(tsk, orig); |
177 | 178 | ||
179 | #ifdef CONFIG_CC_STACKPROTECTOR | ||
180 | tsk->stack_canary = get_random_int(); | ||
181 | #endif | ||
182 | |||
178 | /* One for us, one for whoever does the "release_task()" (usually parent) */ | 183 | /* One for us, one for whoever does the "release_task()" (usually parent) */ |
179 | atomic_set(&tsk->usage,2); | 184 | atomic_set(&tsk->usage,2); |
180 | atomic_set(&tsk->fs_excl, 0); | 185 | atomic_set(&tsk->fs_excl, 0); |
diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 9bad17884513..c088e5542e84 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c | |||
@@ -224,7 +224,14 @@ static int save_trace(struct stack_trace *trace) | |||
224 | trace->max_entries = MAX_STACK_TRACE_ENTRIES - nr_stack_trace_entries; | 224 | trace->max_entries = MAX_STACK_TRACE_ENTRIES - nr_stack_trace_entries; |
225 | trace->entries = stack_trace + nr_stack_trace_entries; | 225 | trace->entries = stack_trace + nr_stack_trace_entries; |
226 | 226 | ||
227 | save_stack_trace(trace, NULL, 0, 3); | 227 | trace->skip = 3; |
228 | trace->all_contexts = 0; | ||
229 | |||
230 | /* Make sure to not recurse in case the the unwinder needs to tak | ||
231 | e locks. */ | ||
232 | lockdep_off(); | ||
233 | save_stack_trace(trace, NULL); | ||
234 | lockdep_on(); | ||
228 | 235 | ||
229 | trace->max_entries = trace->nr_entries; | 236 | trace->max_entries = trace->nr_entries; |
230 | 237 | ||
diff --git a/kernel/panic.c b/kernel/panic.c index 8010b9b17aca..6ceb664fb52a 100644 --- a/kernel/panic.c +++ b/kernel/panic.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/debug_locks.h> | 21 | #include <linux/debug_locks.h> |
22 | 22 | ||
23 | int panic_on_oops; | 23 | int panic_on_oops; |
24 | int panic_on_unrecovered_nmi; | ||
24 | int tainted; | 25 | int tainted; |
25 | static int pause_on_oops; | 26 | static int pause_on_oops; |
26 | static int pause_on_oops_flag; | 27 | static int pause_on_oops_flag; |
@@ -270,3 +271,15 @@ void oops_exit(void) | |||
270 | { | 271 | { |
271 | do_oops_enter_exit(); | 272 | do_oops_enter_exit(); |
272 | } | 273 | } |
274 | |||
275 | #ifdef CONFIG_CC_STACKPROTECTOR | ||
276 | /* | ||
277 | * Called when gcc's -fstack-protector feature is used, and | ||
278 | * gcc detects corruption of the on-stack canary value | ||
279 | */ | ||
280 | void __stack_chk_fail(void) | ||
281 | { | ||
282 | panic("stack-protector: Kernel stack is corrupted"); | ||
283 | } | ||
284 | EXPORT_SYMBOL(__stack_chk_fail); | ||
285 | #endif | ||
diff --git a/kernel/spinlock.c b/kernel/spinlock.c index fb524b009eef..9644a41e0bef 100644 --- a/kernel/spinlock.c +++ b/kernel/spinlock.c | |||
@@ -7,6 +7,11 @@ | |||
7 | * | 7 | * |
8 | * This file contains the spinlock/rwlock implementations for the | 8 | * This file contains the spinlock/rwlock implementations for the |
9 | * SMP and the DEBUG_SPINLOCK cases. (UP-nondebug inlines them) | 9 | * SMP and the DEBUG_SPINLOCK cases. (UP-nondebug inlines them) |
10 | * | ||
11 | * Note that some architectures have special knowledge about the | ||
12 | * stack frames of these functions in their profile_pc. If you | ||
13 | * change anything significant here that could change the stack | ||
14 | * frame contact the architecture maintainers. | ||
10 | */ | 15 | */ |
11 | 16 | ||
12 | #include <linux/linkage.h> | 17 | #include <linux/linkage.h> |
diff --git a/kernel/sys.c b/kernel/sys.c index e236f98f7ec5..3f894775488d 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/tty.h> | 28 | #include <linux/tty.h> |
29 | #include <linux/signal.h> | 29 | #include <linux/signal.h> |
30 | #include <linux/cn_proc.h> | 30 | #include <linux/cn_proc.h> |
31 | #include <linux/getcpu.h> | ||
31 | 32 | ||
32 | #include <linux/compat.h> | 33 | #include <linux/compat.h> |
33 | #include <linux/syscalls.h> | 34 | #include <linux/syscalls.h> |
@@ -2062,3 +2063,33 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
2062 | } | 2063 | } |
2063 | return error; | 2064 | return error; |
2064 | } | 2065 | } |
2066 | |||
2067 | asmlinkage long sys_getcpu(unsigned __user *cpup, unsigned __user *nodep, | ||
2068 | struct getcpu_cache __user *cache) | ||
2069 | { | ||
2070 | int err = 0; | ||
2071 | int cpu = raw_smp_processor_id(); | ||
2072 | if (cpup) | ||
2073 | err |= put_user(cpu, cpup); | ||
2074 | if (nodep) | ||
2075 | err |= put_user(cpu_to_node(cpu), nodep); | ||
2076 | if (cache) { | ||
2077 | /* | ||
2078 | * The cache is not needed for this implementation, | ||
2079 | * but make sure user programs pass something | ||
2080 | * valid. vsyscall implementations can instead make | ||
2081 | * good use of the cache. Only use t0 and t1 because | ||
2082 | * these are available in both 32bit and 64bit ABI (no | ||
2083 | * need for a compat_getcpu). 32bit has enough | ||
2084 | * padding | ||
2085 | */ | ||
2086 | unsigned long t0, t1; | ||
2087 | get_user(t0, &cache->t0); | ||
2088 | get_user(t1, &cache->t1); | ||
2089 | t0++; | ||
2090 | t1++; | ||
2091 | put_user(t0, &cache->t0); | ||
2092 | put_user(t1, &cache->t1); | ||
2093 | } | ||
2094 | return err ? -EFAULT : 0; | ||
2095 | } | ||
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index fd43c3e6786b..bcb3a181dbb2 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -76,8 +76,9 @@ extern int compat_log; | |||
76 | 76 | ||
77 | #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) | 77 | #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) |
78 | int unknown_nmi_panic; | 78 | int unknown_nmi_panic; |
79 | extern int proc_unknown_nmi_panic(ctl_table *, int, struct file *, | 79 | int nmi_watchdog_enabled; |
80 | void __user *, size_t *, loff_t *); | 80 | extern int proc_nmi_enabled(struct ctl_table *, int , struct file *, |
81 | void __user *, size_t *, loff_t *); | ||
81 | #endif | 82 | #endif |
82 | 83 | ||
83 | /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ | 84 | /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ |
@@ -628,11 +629,27 @@ static ctl_table kern_table[] = { | |||
628 | .data = &unknown_nmi_panic, | 629 | .data = &unknown_nmi_panic, |
629 | .maxlen = sizeof (int), | 630 | .maxlen = sizeof (int), |
630 | .mode = 0644, | 631 | .mode = 0644, |
631 | .proc_handler = &proc_unknown_nmi_panic, | 632 | .proc_handler = &proc_dointvec, |
633 | }, | ||
634 | { | ||
635 | .ctl_name = KERN_NMI_WATCHDOG, | ||
636 | .procname = "nmi_watchdog", | ||
637 | .data = &nmi_watchdog_enabled, | ||
638 | .maxlen = sizeof (int), | ||
639 | .mode = 0644, | ||
640 | .proc_handler = &proc_nmi_enabled, | ||
632 | }, | 641 | }, |
633 | #endif | 642 | #endif |
634 | #if defined(CONFIG_X86) | 643 | #if defined(CONFIG_X86) |
635 | { | 644 | { |
645 | .ctl_name = KERN_PANIC_ON_NMI, | ||
646 | .procname = "panic_on_unrecovered_nmi", | ||
647 | .data = &panic_on_unrecovered_nmi, | ||
648 | .maxlen = sizeof(int), | ||
649 | .mode = 0644, | ||
650 | .proc_handler = &proc_dointvec, | ||
651 | }, | ||
652 | { | ||
636 | .ctl_name = KERN_BOOTLOADER_TYPE, | 653 | .ctl_name = KERN_BOOTLOADER_TYPE, |
637 | .procname = "bootloader_type", | 654 | .procname = "bootloader_type", |
638 | .data = &bootloader_type, | 655 | .data = &bootloader_type, |
diff --git a/kernel/unwind.c b/kernel/unwind.c index f69c804c8e62..3430475fcd88 100644 --- a/kernel/unwind.c +++ b/kernel/unwind.c | |||
@@ -603,6 +603,7 @@ int unwind(struct unwind_frame_info *frame) | |||
603 | #define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs]) | 603 | #define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs]) |
604 | const u32 *fde = NULL, *cie = NULL; | 604 | const u32 *fde = NULL, *cie = NULL; |
605 | const u8 *ptr = NULL, *end = NULL; | 605 | const u8 *ptr = NULL, *end = NULL; |
606 | unsigned long pc = UNW_PC(frame) - frame->call_frame; | ||
606 | unsigned long startLoc = 0, endLoc = 0, cfa; | 607 | unsigned long startLoc = 0, endLoc = 0, cfa; |
607 | unsigned i; | 608 | unsigned i; |
608 | signed ptrType = -1; | 609 | signed ptrType = -1; |
@@ -612,7 +613,7 @@ int unwind(struct unwind_frame_info *frame) | |||
612 | 613 | ||
613 | if (UNW_PC(frame) == 0) | 614 | if (UNW_PC(frame) == 0) |
614 | return -EINVAL; | 615 | return -EINVAL; |
615 | if ((table = find_table(UNW_PC(frame))) != NULL | 616 | if ((table = find_table(pc)) != NULL |
616 | && !(table->size & (sizeof(*fde) - 1))) { | 617 | && !(table->size & (sizeof(*fde) - 1))) { |
617 | unsigned long tableSize = table->size; | 618 | unsigned long tableSize = table->size; |
618 | 619 | ||
@@ -647,7 +648,7 @@ int unwind(struct unwind_frame_info *frame) | |||
647 | ptrType & DW_EH_PE_indirect | 648 | ptrType & DW_EH_PE_indirect |
648 | ? ptrType | 649 | ? ptrType |
649 | : ptrType & (DW_EH_PE_FORM|DW_EH_PE_signed)); | 650 | : ptrType & (DW_EH_PE_FORM|DW_EH_PE_signed)); |
650 | if (UNW_PC(frame) >= startLoc && UNW_PC(frame) < endLoc) | 651 | if (pc >= startLoc && pc < endLoc) |
651 | break; | 652 | break; |
652 | cie = NULL; | 653 | cie = NULL; |
653 | } | 654 | } |
@@ -657,16 +658,28 @@ int unwind(struct unwind_frame_info *frame) | |||
657 | state.cieEnd = ptr; /* keep here temporarily */ | 658 | state.cieEnd = ptr; /* keep here temporarily */ |
658 | ptr = (const u8 *)(cie + 2); | 659 | ptr = (const u8 *)(cie + 2); |
659 | end = (const u8 *)(cie + 1) + *cie; | 660 | end = (const u8 *)(cie + 1) + *cie; |
661 | frame->call_frame = 1; | ||
660 | if ((state.version = *ptr) != 1) | 662 | if ((state.version = *ptr) != 1) |
661 | cie = NULL; /* unsupported version */ | 663 | cie = NULL; /* unsupported version */ |
662 | else if (*++ptr) { | 664 | else if (*++ptr) { |
663 | /* check if augmentation size is first (and thus present) */ | 665 | /* check if augmentation size is first (and thus present) */ |
664 | if (*ptr == 'z') { | 666 | if (*ptr == 'z') { |
665 | /* check for ignorable (or already handled) | 667 | while (++ptr < end && *ptr) { |
666 | * nul-terminated augmentation string */ | 668 | switch(*ptr) { |
667 | while (++ptr < end && *ptr) | 669 | /* check for ignorable (or already handled) |
668 | if (strchr("LPR", *ptr) == NULL) | 670 | * nul-terminated augmentation string */ |
671 | case 'L': | ||
672 | case 'P': | ||
673 | case 'R': | ||
674 | continue; | ||
675 | case 'S': | ||
676 | frame->call_frame = 0; | ||
677 | continue; | ||
678 | default: | ||
669 | break; | 679 | break; |
680 | } | ||
681 | break; | ||
682 | } | ||
670 | } | 683 | } |
671 | if (ptr >= end || *ptr) | 684 | if (ptr >= end || *ptr) |
672 | cie = NULL; | 685 | cie = NULL; |
@@ -755,7 +768,7 @@ int unwind(struct unwind_frame_info *frame) | |||
755 | state.org = startLoc; | 768 | state.org = startLoc; |
756 | memcpy(&state.cfa, &badCFA, sizeof(state.cfa)); | 769 | memcpy(&state.cfa, &badCFA, sizeof(state.cfa)); |
757 | /* process instructions */ | 770 | /* process instructions */ |
758 | if (!processCFI(ptr, end, UNW_PC(frame), ptrType, &state) | 771 | if (!processCFI(ptr, end, pc, ptrType, &state) |
759 | || state.loc > endLoc | 772 | || state.loc > endLoc |
760 | || state.regs[retAddrReg].where == Nowhere | 773 | || state.regs[retAddrReg].where == Nowhere |
761 | || state.cfa.reg >= ARRAY_SIZE(reg_info) | 774 | || state.cfa.reg >= ARRAY_SIZE(reg_info) |
@@ -763,6 +776,11 @@ int unwind(struct unwind_frame_info *frame) | |||
763 | || state.cfa.offs % sizeof(unsigned long)) | 776 | || state.cfa.offs % sizeof(unsigned long)) |
764 | return -EIO; | 777 | return -EIO; |
765 | /* update frame */ | 778 | /* update frame */ |
779 | #ifndef CONFIG_AS_CFI_SIGNAL_FRAME | ||
780 | if(frame->call_frame | ||
781 | && !UNW_DEFAULT_RA(state.regs[retAddrReg], state.dataAlign)) | ||
782 | frame->call_frame = 0; | ||
783 | #endif | ||
766 | cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs; | 784 | cfa = FRAME_REG(state.cfa.reg, unsigned long) + state.cfa.offs; |
767 | startLoc = min((unsigned long)UNW_SP(frame), cfa); | 785 | startLoc = min((unsigned long)UNW_SP(frame), cfa); |
768 | endLoc = max((unsigned long)UNW_SP(frame), cfa); | 786 | endLoc = max((unsigned long)UNW_SP(frame), cfa); |
@@ -866,6 +884,7 @@ int unwind_init_frame_info(struct unwind_frame_info *info, | |||
866 | /*const*/ struct pt_regs *regs) | 884 | /*const*/ struct pt_regs *regs) |
867 | { | 885 | { |
868 | info->task = tsk; | 886 | info->task = tsk; |
887 | info->call_frame = 0; | ||
869 | arch_unw_init_frame_info(info, regs); | 888 | arch_unw_init_frame_info(info, regs); |
870 | 889 | ||
871 | return 0; | 890 | return 0; |
@@ -879,6 +898,7 @@ int unwind_init_blocked(struct unwind_frame_info *info, | |||
879 | struct task_struct *tsk) | 898 | struct task_struct *tsk) |
880 | { | 899 | { |
881 | info->task = tsk; | 900 | info->task = tsk; |
901 | info->call_frame = 0; | ||
882 | arch_unw_init_blocked(info); | 902 | arch_unw_init_blocked(info); |
883 | 903 | ||
884 | return 0; | 904 | return 0; |
@@ -894,6 +914,7 @@ int unwind_init_running(struct unwind_frame_info *info, | |||
894 | void *arg) | 914 | void *arg) |
895 | { | 915 | { |
896 | info->task = current; | 916 | info->task = current; |
917 | info->call_frame = 0; | ||
897 | 918 | ||
898 | return arch_unwind_init_running(info, callback, arg); | 919 | return arch_unwind_init_running(info, callback, arg); |
899 | } | 920 | } |