[kernel/f15/master] Restore reliable stack backtraces, and hopefully fix RHBZ #700718
Chuck Ebbert
cebbert at fedoraproject.org
Tue May 3 06:38:55 UTC 2011
commit 50ffc6fec51e26b67f3aa57fb26914c04af6f8f9
Author: Chuck Ebbert <cebbert at redhat.com>
Date: Tue May 3 02:38:59 2011 -0400
Restore reliable stack backtraces, and hopefully fix RHBZ #700718
kernel.spec | 8 +
...dump-info-when-frame-pointer-is-available.patch | 352 ++++++++++++++++++++
2 files changed, 360 insertions(+), 0 deletions(-)
---
diff --git a/kernel.spec b/kernel.spec
index a36c747..233f782 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -732,6 +732,10 @@ Patch12401: scsi-mptsas-prevent-heap-overflows-and-unchecked-reads.patch
# CVE-2011-1581
Patch12402: bonding-incorrect-tx-queue-offset.patch
+# Restore reliable stack backtraces, and hopefully
+# fix RHBZ #700718
+Patch12403: x86-dumpstack-correct-stack-dump-info-when-frame-pointer-is-available.patch
+
%endif
BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root
@@ -1179,6 +1183,9 @@ ApplyPatch linux-2.6-utrace-ptrace.patch
# Architecture patches
# x86(-64)
+# Restore reliable stack backtraces, and hopefully
+# fix RHBZ #700718
+ApplyPatch x86-dumpstack-correct-stack-dump-info-when-frame-pointer-is-available.patch
#
# Intel IOMMU
@@ -1969,6 +1976,7 @@ fi
- [SCSI] mpt2sas: prevent heap overflows and unchecked reads
(CVE-2011-1494, CVE-2011-1495)
- bonding: Incorrect TX queue offset (CVE-2011-1581)
+- Restore reliable stack backtraces, and hopefully fix RHBZ #700718
* Mon May 02 2011 Kyle McMartin <kmcmartin at redhat.com> 2.6.38.5-22
- And to the released 2.6.38.5
diff --git a/x86-dumpstack-correct-stack-dump-info-when-frame-pointer-is-available.patch b/x86-dumpstack-correct-stack-dump-info-when-frame-pointer-is-available.patch
new file mode 100644
index 0000000..36eae4b
--- /dev/null
+++ b/x86-dumpstack-correct-stack-dump-info-when-frame-pointer-is-available.patch
@@ -0,0 +1,352 @@
+From: Namhyung Kim <namhyung at gmail.com>
+Date: Fri, 18 Mar 2011 02:40:06 +0000 (+0900)
+Subject: x86, dumpstack: Correct stack dump info when frame pointer is available
+X-Git-Tag: v2.6.39-rc1~64^2~7
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=e8e999cf3cc733482e390b02ff25a64cecdc0b64
+
+x86, dumpstack: Correct stack dump info when frame pointer is available
+
+Current stack dump code scans entire stack and check each entry
+contains a pointer to kernel code. If CONFIG_FRAME_POINTER=y it
+could mark whether the pointer is valid or not based on value of
+the frame pointer. Invalid entries could be preceded by '?' sign.
+
+However this was not going to happen because scan start point
+was always higher than the frame pointer so that they could not
+meet.
+
+Commit 9c0729dc8062 ("x86: Eliminate bp argument from the stack
+tracing routines") delayed bp acquisition point, so the bp was
+read in lower frame, thus all of the entries were marked
+invalid.
+
+This patch fixes this by reverting above commit while retaining
+stack_frame() helper as suggested by Frederic Weisbecker.
+
+End result looks like below:
+
+before:
+
+ [ 3.508329] Call Trace:
+ [ 3.508551] [<ffffffff814f35c9>] ? panic+0x91/0x199
+ [ 3.508662] [<ffffffff814f3739>] ? printk+0x68/0x6a
+ [ 3.508770] [<ffffffff81a981b2>] ? mount_block_root+0x257/0x26e
+ [ 3.508876] [<ffffffff81a9821f>] ? mount_root+0x56/0x5a
+ [ 3.508975] [<ffffffff81a98393>] ? prepare_namespace+0x170/0x1a9
+ [ 3.509216] [<ffffffff81a9772b>] ? kernel_init+0x1d2/0x1e2
+ [ 3.509335] [<ffffffff81003894>] ? kernel_thread_helper+0x4/0x10
+ [ 3.509442] [<ffffffff814f6880>] ? restore_args+0x0/0x30
+ [ 3.509542] [<ffffffff81a97559>] ? kernel_init+0x0/0x1e2
+ [ 3.509641] [<ffffffff81003890>] ? kernel_thread_helper+0x0/0x10
+
+after:
+
+ [ 3.522991] Call Trace:
+ [ 3.523351] [<ffffffff814f35b9>] panic+0x91/0x199
+ [ 3.523468] [<ffffffff814f3729>] ? printk+0x68/0x6a
+ [ 3.523576] [<ffffffff81a981b2>] mount_block_root+0x257/0x26e
+ [ 3.523681] [<ffffffff81a9821f>] mount_root+0x56/0x5a
+ [ 3.523780] [<ffffffff81a98393>] prepare_namespace+0x170/0x1a9
+ [ 3.523885] [<ffffffff81a9772b>] kernel_init+0x1d2/0x1e2
+ [ 3.523987] [<ffffffff81003894>] kernel_thread_helper+0x4/0x10
+ [ 3.524228] [<ffffffff814f6880>] ? restore_args+0x0/0x30
+ [ 3.524345] [<ffffffff81a97559>] ? kernel_init+0x0/0x1e2
+ [ 3.524445] [<ffffffff81003890>] ? kernel_thread_helper+0x0/0x10
+
+ -v5:
+ * fix build breakage with oprofile
+
+ -v4:
+ * use 0 instead of regs->bp
+ * separate out printk changes
+
+ -v3:
+ * apply comment from Frederic
+ * add a couple of printk fixes
+
+Signed-off-by: Namhyung Kim <namhyung at gmail.com>
+Acked-by: Peter Zijlstra <a.p.zijlstra at chello.nl>
+Acked-by: Frederic Weisbecker <fweisbec at gmail.com>
+Cc: Soren Sandmann <ssp at redhat.com>
+Cc: Paul Mackerras <paulus at samba.org>
+Cc: Arnaldo Carvalho de Melo <acme at redhat.com>
+Cc: Robert Richter <robert.richter at amd.com>
+LKML-Reference: <1300416006-3163-1-git-send-email-namhyung at gmail.com>
+Signed-off-by: Ingo Molnar <mingo at elte.hu>
+---
+
+diff --git a/arch/x86/include/asm/kdebug.h b/arch/x86/include/asm/kdebug.h
+index 518bbbb..fe2cc6e 100644
+--- a/arch/x86/include/asm/kdebug.h
++++ b/arch/x86/include/asm/kdebug.h
+@@ -26,7 +26,7 @@ extern void die(const char *, struct pt_regs *,long);
+ extern int __must_check __die(const char *, struct pt_regs *, long);
+ extern void show_registers(struct pt_regs *regs);
+ extern void show_trace(struct task_struct *t, struct pt_regs *regs,
+- unsigned long *sp);
++ unsigned long *sp, unsigned long bp);
+ extern void __show_regs(struct pt_regs *regs, int all);
+ extern void show_regs(struct pt_regs *regs);
+ extern unsigned long oops_begin(void);
+diff --git a/arch/x86/include/asm/stacktrace.h b/arch/x86/include/asm/stacktrace.h
+index 52b5c7e..d7e89c8 100644
+--- a/arch/x86/include/asm/stacktrace.h
++++ b/arch/x86/include/asm/stacktrace.h
+@@ -47,7 +47,7 @@ struct stacktrace_ops {
+ };
+
+ void dump_trace(struct task_struct *tsk, struct pt_regs *regs,
+- unsigned long *stack,
++ unsigned long *stack, unsigned long bp,
+ const struct stacktrace_ops *ops, void *data);
+
+ #ifdef CONFIG_X86_32
+@@ -86,11 +86,11 @@ stack_frame(struct task_struct *task, struct pt_regs *regs)
+
+ extern void
+ show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
+- unsigned long *stack, char *log_lvl);
++ unsigned long *stack, unsigned long bp, char *log_lvl);
+
+ extern void
+ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
+- unsigned long *sp, char *log_lvl);
++ unsigned long *sp, unsigned long bp, char *log_lvl);
+
+ extern unsigned int code_bytes;
+
+diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
+index 279bc9d..3061276 100644
+--- a/arch/x86/kernel/cpu/perf_event.c
++++ b/arch/x86/kernel/cpu/perf_event.c
+@@ -1792,7 +1792,7 @@ perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
+
+ perf_callchain_store(entry, regs->ip);
+
+- dump_trace(NULL, regs, NULL, &backtrace_ops, entry);
++ dump_trace(NULL, regs, NULL, 0, &backtrace_ops, entry);
+ }
+
+ #ifdef CONFIG_COMPAT
+diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
+index 220a1c1..999e279 100644
+--- a/arch/x86/kernel/dumpstack.c
++++ b/arch/x86/kernel/dumpstack.c
+@@ -175,21 +175,21 @@ static const struct stacktrace_ops print_trace_ops = {
+
+ void
+ show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
+- unsigned long *stack, char *log_lvl)
++ unsigned long *stack, unsigned long bp, char *log_lvl)
+ {
+ printk("%sCall Trace:\n", log_lvl);
+- dump_trace(task, regs, stack, &print_trace_ops, log_lvl);
++ dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
+ }
+
+ void show_trace(struct task_struct *task, struct pt_regs *regs,
+- unsigned long *stack)
++ unsigned long *stack, unsigned long bp)
+ {
+- show_trace_log_lvl(task, regs, stack, "");
++ show_trace_log_lvl(task, regs, stack, bp, "");
+ }
+
+ void show_stack(struct task_struct *task, unsigned long *sp)
+ {
+- show_stack_log_lvl(task, NULL, sp, "");
++ show_stack_log_lvl(task, NULL, sp, 0, "");
+ }
+
+ /*
+@@ -197,14 +197,16 @@ void show_stack(struct task_struct *task, unsigned long *sp)
+ */
+ void dump_stack(void)
+ {
++ unsigned long bp;
+ unsigned long stack;
+
++ bp = stack_frame(current, NULL);
+ printk("Pid: %d, comm: %.20s %s %s %.*s\n",
+ current->pid, current->comm, print_tainted(),
+ init_utsname()->release,
+ (int)strcspn(init_utsname()->version, " "),
+ init_utsname()->version);
+- show_trace(NULL, NULL, &stack);
++ show_trace(NULL, NULL, &stack, bp);
+ }
+ EXPORT_SYMBOL(dump_stack);
+
+diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
+index 74cc1ed..3b97a80 100644
+--- a/arch/x86/kernel/dumpstack_32.c
++++ b/arch/x86/kernel/dumpstack_32.c
+@@ -17,12 +17,11 @@
+ #include <asm/stacktrace.h>
+
+
+-void dump_trace(struct task_struct *task,
+- struct pt_regs *regs, unsigned long *stack,
++void dump_trace(struct task_struct *task, struct pt_regs *regs,
++ unsigned long *stack, unsigned long bp,
+ const struct stacktrace_ops *ops, void *data)
+ {
+ int graph = 0;
+- unsigned long bp;
+
+ if (!task)
+ task = current;
+@@ -35,7 +34,9 @@ void dump_trace(struct task_struct *task,
+ stack = (unsigned long *)task->thread.sp;
+ }
+
+- bp = stack_frame(task, regs);
++ if (!bp)
++ bp = stack_frame(task, regs);
++
+ for (;;) {
+ struct thread_info *context;
+
+@@ -55,7 +56,7 @@ EXPORT_SYMBOL(dump_trace);
+
+ void
+ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
+- unsigned long *sp, char *log_lvl)
++ unsigned long *sp, unsigned long bp, char *log_lvl)
+ {
+ unsigned long *stack;
+ int i;
+@@ -77,7 +78,7 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
+ touch_nmi_watchdog();
+ }
+ printk(KERN_CONT "\n");
+- show_trace_log_lvl(task, regs, sp, log_lvl);
++ show_trace_log_lvl(task, regs, sp, bp, log_lvl);
+ }
+
+
+@@ -102,7 +103,7 @@ void show_registers(struct pt_regs *regs)
+ u8 *ip;
+
+ printk(KERN_EMERG "Stack:\n");
+- show_stack_log_lvl(NULL, regs, ®s->sp, KERN_EMERG);
++ show_stack_log_lvl(NULL, regs, ®s->sp, 0, KERN_EMERG);
+
+ printk(KERN_EMERG "Code: ");
+
+diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
+index a6b6fcf..e71c98d 100644
+--- a/arch/x86/kernel/dumpstack_64.c
++++ b/arch/x86/kernel/dumpstack_64.c
+@@ -139,8 +139,8 @@ fixup_bp_irq_link(unsigned long bp, unsigned long *stack,
+ * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
+ */
+
+-void dump_trace(struct task_struct *task,
+- struct pt_regs *regs, unsigned long *stack,
++void dump_trace(struct task_struct *task, struct pt_regs *regs,
++ unsigned long *stack, unsigned long bp,
+ const struct stacktrace_ops *ops, void *data)
+ {
+ const unsigned cpu = get_cpu();
+@@ -150,7 +150,6 @@ void dump_trace(struct task_struct *task,
+ struct thread_info *tinfo;
+ int graph = 0;
+ unsigned long dummy;
+- unsigned long bp;
+
+ if (!task)
+ task = current;
+@@ -161,7 +160,8 @@ void dump_trace(struct task_struct *task,
+ stack = (unsigned long *)task->thread.sp;
+ }
+
+- bp = stack_frame(task, regs);
++ if (!bp)
++ bp = stack_frame(task, regs);
+ /*
+ * Print function call entries in all stacks, starting at the
+ * current stack address. If the stacks consist of nested
+@@ -225,7 +225,7 @@ EXPORT_SYMBOL(dump_trace);
+
+ void
+ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
+- unsigned long *sp, char *log_lvl)
++ unsigned long *sp, unsigned long bp, char *log_lvl)
+ {
+ unsigned long *irq_stack_end;
+ unsigned long *irq_stack;
+@@ -269,7 +269,7 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
+ preempt_enable();
+
+ printk(KERN_CONT "\n");
+- show_trace_log_lvl(task, regs, sp, log_lvl);
++ show_trace_log_lvl(task, regs, sp, bp, log_lvl);
+ }
+
+ void show_registers(struct pt_regs *regs)
+@@ -298,7 +298,7 @@ void show_registers(struct pt_regs *regs)
+
+ printk(KERN_EMERG "Stack:\n");
+ show_stack_log_lvl(NULL, regs, (unsigned long *)sp,
+- KERN_EMERG);
++ 0, KERN_EMERG);
+
+ printk(KERN_EMERG "Code: ");
+
+diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
+index 99fa3ad..d46cbe4 100644
+--- a/arch/x86/kernel/process.c
++++ b/arch/x86/kernel/process.c
+@@ -87,7 +87,7 @@ void exit_thread(void)
+ void show_regs(struct pt_regs *regs)
+ {
+ show_registers(regs);
+- show_trace(NULL, regs, (unsigned long *)kernel_stack_pointer(regs));
++ show_trace(NULL, regs, (unsigned long *)kernel_stack_pointer(regs), 0);
+ }
+
+ void show_regs_common(void)
+diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c
+index 938c8e1..6515733 100644
+--- a/arch/x86/kernel/stacktrace.c
++++ b/arch/x86/kernel/stacktrace.c
+@@ -73,7 +73,7 @@ static const struct stacktrace_ops save_stack_ops_nosched = {
+ */
+ void save_stack_trace(struct stack_trace *trace)
+ {
+- dump_trace(current, NULL, NULL, &save_stack_ops, trace);
++ dump_trace(current, NULL, NULL, 0, &save_stack_ops, trace);
+ if (trace->nr_entries < trace->max_entries)
+ trace->entries[trace->nr_entries++] = ULONG_MAX;
+ }
+@@ -81,14 +81,14 @@ EXPORT_SYMBOL_GPL(save_stack_trace);
+
+ void save_stack_trace_regs(struct stack_trace *trace, struct pt_regs *regs)
+ {
+- dump_trace(current, regs, NULL, &save_stack_ops, trace);
++ dump_trace(current, regs, NULL, 0, &save_stack_ops, trace);
+ if (trace->nr_entries < trace->max_entries)
+ trace->entries[trace->nr_entries++] = ULONG_MAX;
+ }
+
+ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
+ {
+- dump_trace(tsk, NULL, NULL, &save_stack_ops_nosched, trace);
++ dump_trace(tsk, NULL, NULL, 0, &save_stack_ops_nosched, trace);
+ if (trace->nr_entries < trace->max_entries)
+ trace->entries[trace->nr_entries++] = ULONG_MAX;
+ }
+diff --git a/arch/x86/oprofile/backtrace.c b/arch/x86/oprofile/backtrace.c
+index 72cbec1..2d49d4e 100644
+--- a/arch/x86/oprofile/backtrace.c
++++ b/arch/x86/oprofile/backtrace.c
+@@ -126,7 +126,7 @@ x86_backtrace(struct pt_regs * const regs, unsigned int depth)
+ if (!user_mode_vm(regs)) {
+ unsigned long stack = kernel_stack_pointer(regs);
+ if (depth)
+- dump_trace(NULL, regs, (unsigned long *)stack,
++ dump_trace(NULL, regs, (unsigned long *)stack, 0,
+ &backtrace_ops, &depth);
+ return;
+ }
More information about the scm-commits
mailing list