[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20100408123209.GA6096@nowhere>
Date: Thu, 8 Apr 2010 14:32:11 +0200
From: Frederic Weisbecker <fweisbec@...il.com>
To: Eric Dumazet <eric.dumazet@...il.com>
Cc: Ingo Molnar <mingo@...e.hu>, LKML <linux-kernel@...r.kernel.org>,
Peter Zijlstra <a.p.zijlstra@...llo.nl>,
Arnaldo Carvalho de Melo <acme@...hat.com>,
Paul Mackerras <paulus@...ba.org>,
David Miller <davem@...emloft.net>,
Archs <linux-arch@...r.kernel.org>
Subject: [PATCH] perf: Fix unsafe frame rewinding with hot regs fetching
On Thu, Apr 08, 2010 at 11:57:20AM +0200, Eric Dumazet wrote:
> Hello
>
> Current linux-2.6 tree panics on my dev machine
>
> 64 bit kernel, 32bit user land
> CONFIG_FRAME_POINTER=y
>
> perf timechart record &
>
> Instant crash
>
> Call Trace:
> perf_trace_sched_switch+0xd5/0x120
> schedule+0x6b5/0x860
> retint_careful+0xd/0x21
>
> RIP ffffffff81010955 perf_arch_fetch_caller_regs+0x15/0x40
> CR2: 00000000d21f1422
>
>
> rewind_frame_pointer() is probably wrong.
>
> No test performed to check frame is in current stack, or
> that (!user_mode_vm(regs))
>
>
> static inline unsigned long rewind_frame_pointer(int n)
> {
> struct stack_frame *frame;
>
> get_bp(frame);
>
> #ifdef CONFIG_FRAME_POINTER
> while (n--)
> frame = frame->next_frame;
> #endif
>
> return (unsigned long)frame;
> }
>
>
>
Can you please test this fix?
Thanks.
---
>From 60d5c4e8498efc4a01abceef54ad3bc91993bf41 Mon Sep 17 00:00:00 2001
From: Frederic Weisbecker <fweisbec@...il.com>
Date: Thu, 8 Apr 2010 14:05:50 +0200
Subject: [PATCH] perf: Fix unsafe frame rewinding with hot regs fetching
When we fetch the hot regs and rewind to the nth caller, it
might happen that we dereference a frame pointer outside the
kernel stack boundaries, like in this example:
perf_trace_sched_switch+0xd5/0x120
schedule+0x6b5/0x860
retint_careful+0xd/0x21
Since we directly dereference a userspace frame pointer here while
rewinding behind retint_careful, this may end up in a crash.
Fix this by simply using probe_kernel_address() when we rewind the
frame pointer.
This issue will have a much more proper fix in the next version of the
perf_arch_fetch_caller_regs() API that will only need to rewind to the
first caller.
Reported-by: Eric Dumazet <eric.dumazet@...il.com>
Signed-off-by: Frederic Weisbecker <fweisbec@...il.com>
Cc: Peter Zijlstra <a.p.zijlstra@...llo.nl>
Cc: Arnaldo Carvalho de Melo <acme@...hat.com>
Cc: Paul Mackerras <paulus@...ba.org>
Cc: David Miller <davem@...emloft.net>
Cc: Archs <linux-arch@...r.kernel.org>
---
arch/x86/kernel/dumpstack.h | 8 ++++++--
1 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kernel/dumpstack.h b/arch/x86/kernel/dumpstack.h
index e39e771..e1a93be 100644
--- a/arch/x86/kernel/dumpstack.h
+++ b/arch/x86/kernel/dumpstack.h
@@ -14,6 +14,8 @@
#define get_bp(bp) asm("movq %%rbp, %0" : "=r" (bp) :)
#endif
+#include <linux/uaccess.h>
+
extern void
show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
unsigned long *stack, unsigned long bp, char *log_lvl);
@@ -42,8 +44,10 @@ static inline unsigned long rewind_frame_pointer(int n)
get_bp(frame);
#ifdef CONFIG_FRAME_POINTER
- while (n--)
- frame = frame->next_frame;
+ while (n--) {
+ if (probe_kernel_address(&frame->next_frame, frame))
+ break;
+ }
#endif
return (unsigned long)frame;
--
1.6.2.3
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists