Commit a8b7a923 authored by Josh Poimboeuf's avatar Josh Poimboeuf Committed by Ingo Molnar

x86/unwind: Silence entry-related warnings

A few people have reported unwinder warnings like the following:

  WARNING: kernel stack frame pointer at ffffc90000fe7ff0 in rsync:1157 has bad value           (null)
  unwind stack type:0 next_sp:          (null) mask:2 graph_idx:0
  ffffc90000fe7f98: ffffc90000fe7ff0 (0xffffc90000fe7ff0)
  ffffc90000fe7fa0: ffffffffb7000f56 (trace_hardirqs_off_thunk+0x1a/0x1c)
  ffffc90000fe7fa8: 0000000000000246 (0x246)
  ffffc90000fe7fb0: 0000000000000000 ...
  ffffc90000fe7fc0: 00007ffe3af639bc (0x7ffe3af639bc)
  ffffc90000fe7fc8: 0000000000000006 (0x6)
  ffffc90000fe7fd0: 00007f80af433fc5 (0x7f80af433fc5)
  ffffc90000fe7fd8: 00007ffe3af638e0 (0x7ffe3af638e0)
  ffffc90000fe7fe0: 00007ffe3af638e0 (0x7ffe3af638e0)
  ffffc90000fe7fe8: 00007ffe3af63970 (0x7ffe3af63970)
  ffffc90000fe7ff0: 0000000000000000 ...
  ffffc90000fe7ff8: ffffffffb7b74b9a (entry_SYSCALL_64_after_swapgs+0x17/0x4f)

This warning can happen when unwinding a code path where an interrupt
occurred in x86 entry code before it set up the first stack frame.
Silently ignore any warnings for this case.
Reported-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Reported-by: default avatarDave Jones <davej@codemonkey.org.uk>
Signed-off-by: default avatarJosh Poimboeuf <jpoimboe@redhat.com>
Acked-by: default avatarThomas Gleixner <tglx@linutronix.de>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Fixes: c32c47c6 ("x86/unwind: Warn on bad frame pointer")
Link: http://lkml.kernel.org/r/dbd6838826466a60dc23a52098185bc973ce2f1e.1492020577.git.jpoimboe@redhat.comSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 6bcdf9d5
...@@ -12,6 +12,7 @@ struct unwind_state { ...@@ -12,6 +12,7 @@ struct unwind_state {
struct task_struct *task; struct task_struct *task;
int graph_idx; int graph_idx;
#ifdef CONFIG_FRAME_POINTER #ifdef CONFIG_FRAME_POINTER
bool got_irq;
unsigned long *bp, *orig_sp; unsigned long *bp, *orig_sp;
struct pt_regs *regs; struct pt_regs *regs;
unsigned long ip; unsigned long ip;
......
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/sched/task.h> #include <linux/sched/task.h>
#include <linux/sched/task_stack.h> #include <linux/sched/task_stack.h>
#include <linux/interrupt.h>
#include <asm/sections.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/bitops.h> #include <asm/bitops.h>
#include <asm/stacktrace.h> #include <asm/stacktrace.h>
...@@ -72,6 +74,21 @@ static size_t regs_size(struct pt_regs *regs) ...@@ -72,6 +74,21 @@ static size_t regs_size(struct pt_regs *regs)
return sizeof(*regs); return sizeof(*regs);
} }
static bool in_entry_code(unsigned long ip)
{
char *addr = (char *)ip;
if (addr >= __entry_text_start && addr < __entry_text_end)
return true;
#if defined(CONFIG_FUNCTION_GRAPH_TRACER) || defined(CONFIG_KASAN)
if (addr >= __irqentry_text_start && addr < __irqentry_text_end)
return true;
#endif
return false;
}
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
#define GCC_REALIGN_WORDS 3 #define GCC_REALIGN_WORDS 3
#else #else
...@@ -144,6 +161,7 @@ static bool update_stack_state(struct unwind_state *state, ...@@ -144,6 +161,7 @@ static bool update_stack_state(struct unwind_state *state,
if (regs) { if (regs) {
frame = (unsigned long *)regs; frame = (unsigned long *)regs;
len = regs_size(regs); len = regs_size(regs);
state->got_irq = true;
} else { } else {
frame = next_bp; frame = next_bp;
len = FRAME_HEADER_SIZE; len = FRAME_HEADER_SIZE;
...@@ -239,16 +257,8 @@ bool unwind_next_frame(struct unwind_state *state) ...@@ -239,16 +257,8 @@ bool unwind_next_frame(struct unwind_state *state)
next_bp = (unsigned long *)READ_ONCE_TASK_STACK(state->task, *state->bp); next_bp = (unsigned long *)READ_ONCE_TASK_STACK(state->task, *state->bp);
/* Move to the next frame if it's safe: */ /* Move to the next frame if it's safe: */
if (!update_stack_state(state, next_bp)) { if (!update_stack_state(state, next_bp))
/*
* Don't warn on bad regs->bp. An interrupt in entry code
* might cause a false positive warning.
*/
if (state->regs)
goto the_end;
goto bad_address; goto bad_address;
}
return true; return true;
...@@ -263,6 +273,13 @@ bool unwind_next_frame(struct unwind_state *state) ...@@ -263,6 +273,13 @@ bool unwind_next_frame(struct unwind_state *state)
if (state->task != current) if (state->task != current)
goto the_end; goto the_end;
/*
* Don't warn if the unwinder got lost due to an interrupt in entry
* code before the stack was set up:
*/
if (state->got_irq && in_entry_code(state->ip))
goto the_end;
if (state->regs) { if (state->regs) {
printk_deferred_once(KERN_WARNING printk_deferred_once(KERN_WARNING
"WARNING: kernel stack regs at %p in %s:%d has bad 'bp' value %p\n", "WARNING: kernel stack regs at %p in %s:%d has bad 'bp' value %p\n",
...@@ -289,6 +306,7 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task, ...@@ -289,6 +306,7 @@ void __unwind_start(struct unwind_state *state, struct task_struct *task,
memset(state, 0, sizeof(*state)); memset(state, 0, sizeof(*state));
state->task = task; state->task = task;
state->got_irq = (regs);
/* Don't even attempt to start from user mode regs: */ /* Don't even attempt to start from user mode regs: */
if (regs && user_mode(regs)) { if (regs && user_mode(regs)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment