aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2010-03-02 20:25:22 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2010-04-01 19:01:15 -0400
commit1dc877c1e87d46ba2bfaac30af5e1dde77b72d1c (patch)
tree590d16a1a022b20777ad3ee53250c22299f26834 /arch
parent429f074ef0e55415bb6bd72acca5be2e952719da (diff)
x86/stacktrace: Don't dereference bad frame pointers
commit 29044ad1509ecc229f1d5a31aeed7a8dc61a71c4 upstream. Callers of a stacktrace might pass bad frame pointers. Those are usually checked for safety in stack walking helpers before any dereferencing, but this is not the case when we need to go through one more frame pointer that backlinks the irq stack to the previous one, as we don't have any reliable address boudaries to compare this frame pointer against. This raises crashes when we record callchains for ftrace events with perf because we don't use the right helpers to capture registers there. We get wrong frame pointers as we call task_pt_regs() even on kernel threads, which is a wrong thing as it gives us the initial state of any kernel threads freshly created. This is even not what we want for user tasks. What we want is a hot snapshot of registers when the ftrace event triggers, not the state before a task entered the kernel. This requires more thoughts to do it correctly though. So first put a guardian to ensure the given frame pointer can be dereferenced to avoid crashes. We'll think about how to fix the callers in a subsequent patch. Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kernel/dumpstack_64.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index 0ad9597073f5..a6c906c9b193 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -125,9 +125,15 @@ fixup_bp_irq_link(unsigned long bp, unsigned long *stack,
125{ 125{
126#ifdef CONFIG_FRAME_POINTER 126#ifdef CONFIG_FRAME_POINTER
127 struct stack_frame *frame = (struct stack_frame *)bp; 127 struct stack_frame *frame = (struct stack_frame *)bp;
128 unsigned long next;
128 129
129 if (!in_irq_stack(stack, irq_stack, irq_stack_end)) 130 if (!in_irq_stack(stack, irq_stack, irq_stack_end)) {
130 return (unsigned long)frame->next_frame; 131 if (!probe_kernel_address(&frame->next_frame, next))
132 return next;
133 else
134 WARN_ONCE(1, "Perf: bad frame pointer = %p in "
135 "callchain\n", &frame->next_frame);
136 }
131#endif 137#endif
132 return bp; 138 return bp;
133} 139}