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: Daniel Borkmann <daniel@iogearbox.net>
Reported-by: Dave Jones <davej@codemonkey.org.uk>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Acked-by: Thomas 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: c32c47c68a
("x86/unwind: Warn on bad frame pointer")
Link: http://lkml.kernel.org/r/dbd6838826466a60dc23a52098185bc973ce2f1e.1492020577.git.jpoimboe@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
80 lines
1.7 KiB
C
80 lines
1.7 KiB
C
#ifndef _ASM_X86_UNWIND_H
|
|
#define _ASM_X86_UNWIND_H
|
|
|
|
#include <linux/sched.h>
|
|
#include <linux/ftrace.h>
|
|
#include <asm/ptrace.h>
|
|
#include <asm/stacktrace.h>
|
|
|
|
struct unwind_state {
|
|
struct stack_info stack_info;
|
|
unsigned long stack_mask;
|
|
struct task_struct *task;
|
|
int graph_idx;
|
|
#ifdef CONFIG_FRAME_POINTER
|
|
bool got_irq;
|
|
unsigned long *bp, *orig_sp;
|
|
struct pt_regs *regs;
|
|
unsigned long ip;
|
|
#else
|
|
unsigned long *sp;
|
|
#endif
|
|
};
|
|
|
|
void __unwind_start(struct unwind_state *state, struct task_struct *task,
|
|
struct pt_regs *regs, unsigned long *first_frame);
|
|
|
|
bool unwind_next_frame(struct unwind_state *state);
|
|
|
|
unsigned long unwind_get_return_address(struct unwind_state *state);
|
|
|
|
static inline bool unwind_done(struct unwind_state *state)
|
|
{
|
|
return state->stack_info.type == STACK_TYPE_UNKNOWN;
|
|
}
|
|
|
|
static inline
|
|
void unwind_start(struct unwind_state *state, struct task_struct *task,
|
|
struct pt_regs *regs, unsigned long *first_frame)
|
|
{
|
|
first_frame = first_frame ? : get_stack_pointer(task, regs);
|
|
|
|
__unwind_start(state, task, regs, first_frame);
|
|
}
|
|
|
|
#ifdef CONFIG_FRAME_POINTER
|
|
|
|
static inline
|
|
unsigned long *unwind_get_return_address_ptr(struct unwind_state *state)
|
|
{
|
|
if (unwind_done(state))
|
|
return NULL;
|
|
|
|
return state->regs ? &state->regs->ip : state->bp + 1;
|
|
}
|
|
|
|
static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state)
|
|
{
|
|
if (unwind_done(state))
|
|
return NULL;
|
|
|
|
return state->regs;
|
|
}
|
|
|
|
#else /* !CONFIG_FRAME_POINTER */
|
|
|
|
static inline
|
|
unsigned long *unwind_get_return_address_ptr(struct unwind_state *state)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
static inline struct pt_regs *unwind_get_entry_regs(struct unwind_state *state)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
#endif /* CONFIG_FRAME_POINTER */
|
|
|
|
#endif /* _ASM_X86_UNWIND_H */
|