Restore reliable stack backtraces, and hopefully fix RHBZ #700718
This commit is contained in:
parent
e883ed16c1
commit
50ffc6fec5
|
@ -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@redhat.com> 2.6.38.5-22
|
||||
- And to the released 2.6.38.5
|
||||
|
|
|
@ -0,0 +1,352 @@
|
|||
From: Namhyung Kim <namhyung@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@gmail.com>
|
||||
Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
|
||||
Acked-by: Frederic Weisbecker <fweisbec@gmail.com>
|
||||
Cc: Soren Sandmann <ssp@redhat.com>
|
||||
Cc: Paul Mackerras <paulus@samba.org>
|
||||
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
|
||||
Cc: Robert Richter <robert.richter@amd.com>
|
||||
LKML-Reference: <1300416006-3163-1-git-send-email-namhyung@gmail.com>
|
||||
Signed-off-by: Ingo Molnar <mingo@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;
|
||||
}
|
Loading…
Reference in New Issue