aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/fork.c5
-rw-r--r--kernel/lockdep.c9
-rw-r--r--kernel/panic.c13
-rw-r--r--kernel/spinlock.c5
-rw-r--r--kernel/sys.c31
-rw-r--r--kernel/sysctl.c23
-rw-r--r--kernel/unwind.c35
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
231e 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
23int panic_on_oops; 23int panic_on_oops;
24int panic_on_unrecovered_nmi;
24int tainted; 25int tainted;
25static int pause_on_oops; 26static int pause_on_oops;
26static int pause_on_oops_flag; 27static 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 */
280void __stack_chk_fail(void)
281{
282 panic("stack-protector: Kernel stack is corrupted");
283}
284EXPORT_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
2067asmlinkage 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)
78int unknown_nmi_panic; 78int unknown_nmi_panic;
79extern int proc_unknown_nmi_panic(ctl_table *, int, struct file *, 79int nmi_watchdog_enabled;
80 void __user *, size_t *, loff_t *); 80extern 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}