Re: BUG: KASAN: stack-out-of-bounds in unwind_next_frame+0x1df5/0x2650
From: Josh Poimboeuf <hidden>
Date: 2021-02-03 19:07:36
Also in:
bpf, dm-devel, lkml, netdev
Subsystem:
documentation, the rest, x86 architecture (32-bit and 64-bit), x86 stack unwinding · Maintainers:
Jonathan Corbet, Linus Torvalds, Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, Josh Poimboeuf, Peter Zijlstra
On Wed, Feb 03, 2021 at 09:46:55AM -0800, Ivan Babrou wrote:
quoted
Can you pretty please not line-wrap console output? It's unreadable.GMail doesn't make it easy, I'll send a link to a pastebin next time. Let me know if you'd like me to regenerate the decoded stack.quoted
quoted
edfd9b7838ba5e47f19ad8466d0565aba5c59bf0 is the first bad commit commit edfd9b7838ba5e47f19ad8466d0565aba5c59bf0Not sure what tree you're on, but that's not the upstream commit.I mentioned that it's a rebased core-static_call-2020-10-12 tag and added a link to the upstream hash right below.quoted
quoted
Author: Steven Rostedt (VMware) [off-list ref] Date: Tue Aug 18 15:57:52 2020 +0200 tracepoint: Optimize using static_call()There's a known issue with that patch, can you try: http://lkml.kernel.org/r/20210202220121.435051654@goodmis.orgI've tried it on top of core-static_call-2020-10-12 tag rebased on top of v5.9 (to make it reproducible), and the patch did not help. Do I need to apply the whole series or something else?
Can you recreate with this patch, and add "unwind_debug" to the cmdline? It will spit out a bunch of stack data. From: Josh Poimboeuf <redacted> Subject: [PATCH] Subject: [PATCH] x86/unwind: Add 'unwind_debug' cmdline option Sometimes the one-line ORC unwinder warnings aren't very helpful. Take the existing frame pointer unwind_dump() and make it useful for all unwinders. I don't want to be too aggressive about enabling the dumps, so for now they're only enabled with the use of a new 'unwind_debug' cmdline option. When enabled, it will dump the full contents of the stack when an error condition is encountered, or when dump_stack() is called. Signed-off-by: Josh Poimboeuf <redacted> --- .../admin-guide/kernel-parameters.txt | 6 +++ arch/x86/include/asm/unwind.h | 3 ++ arch/x86/kernel/dumpstack.c | 39 ++++++++++++++ arch/x86/kernel/unwind_frame.c | 51 +++---------------- arch/x86/kernel/unwind_orc.c | 5 +- 5 files changed, 58 insertions(+), 46 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 3d6604a949f8..d29689aa62a2 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt@@ -5521,6 +5521,12 @@ unknown_nmi_panic [X86] Cause panic on unknown NMI. + unwind_debug [X86-64] + Enable unwinder debug output. This can be + useful for debugging certain unwinder error + conditions, including corrupt stacks and + bad/missing unwinder metadata. + usbcore.authorized_default= [USB] Default USB device authorization: (default -1 = authorized except for wireless USB,
diff --git a/arch/x86/include/asm/unwind.h b/arch/x86/include/asm/unwind.h
index 70fc159ebe69..5101d7ef7912 100644
--- a/arch/x86/include/asm/unwind.h
+++ b/arch/x86/include/asm/unwind.h@@ -123,4 +123,7 @@ static inline bool task_on_another_cpu(struct task_struct *task) #endif } +extern bool unwind_debug __ro_after_init; +void unwind_dump(struct unwind_state *state); + #endif /* _ASM_X86_UNWIND_H */
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index 299c20f0a38b..febfd5b7f62a 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c@@ -29,6 +29,42 @@ static int die_counter; static struct pt_regs exec_summary_regs; +bool unwind_debug __ro_after_init; +static int __init unwind_debug_cmdline(char *str) +{ + unwind_debug = true; + return 0; +} +early_param("unwind_debug", unwind_debug_cmdline); + +void unwind_dump(struct unwind_state *state) +{ + unsigned long word, *sp; + struct stack_info stack_info = {0}; + unsigned long visit_mask = 0; + + printk_deferred("unwinder dump: stack type:%d next_sp:%p mask:0x%lx graph_idx:%d\n", + state->stack_info.type, state->stack_info.next_sp, + state->stack_mask, state->graph_idx); + + sp = state->task == current ? __builtin_frame_address(0) + : (void *)state->task->thread.sp; + + for (; sp; sp = PTR_ALIGN(stack_info.next_sp, sizeof(long))) { + if (get_stack_info(sp, state->task, &stack_info, &visit_mask)) + break; + + for (; sp < stack_info.end; sp++) { + + word = READ_ONCE_NOCHECK(*sp); + + printk_deferred("%0*lx: %0*lx (%pB)\n", BITS_PER_LONG/4, + (unsigned long)sp, BITS_PER_LONG/4, + word, (void *)word); + } + } +} + bool noinstr in_task_stack(unsigned long *stack, struct task_struct *task, struct stack_info *info) {
@@ -301,6 +337,9 @@ static void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, if (stack_name) printk("%s </%s>\n", log_lvl, stack_name); } + + if (unwind_debug) + unwind_dump(&state); } void show_stack(struct task_struct *task, unsigned long *sp,
diff --git a/arch/x86/kernel/unwind_frame.c b/arch/x86/kernel/unwind_frame.c
index d7c44b257f7f..6bcdf6ecad65 100644
--- a/arch/x86/kernel/unwind_frame.c
+++ b/arch/x86/kernel/unwind_frame.c@@ -28,48 +28,6 @@ unsigned long *unwind_get_return_address_ptr(struct unwind_state *state) return state->regs ? &state->regs->ip : state->bp + 1; } -static void unwind_dump(struct unwind_state *state) -{ - static bool dumped_before = false; - bool prev_zero, zero = false; - unsigned long word, *sp; - struct stack_info stack_info = {0}; - unsigned long visit_mask = 0; - - if (dumped_before) - return; - - dumped_before = true; - - printk_deferred("unwind stack type:%d next_sp:%p mask:0x%lx graph_idx:%d\n", - state->stack_info.type, state->stack_info.next_sp, - state->stack_mask, state->graph_idx); - - for (sp = PTR_ALIGN(state->orig_sp, sizeof(long)); sp; - sp = PTR_ALIGN(stack_info.next_sp, sizeof(long))) { - if (get_stack_info(sp, state->task, &stack_info, &visit_mask)) - break; - - for (; sp < stack_info.end; sp++) { - - word = READ_ONCE_NOCHECK(*sp); - - prev_zero = zero; - zero = word == 0; - - if (zero) { - if (!prev_zero) - printk_deferred("%p: %0*x ...\n", - sp, BITS_PER_LONG/4, 0); - continue; - } - - printk_deferred("%p: %0*lx (%pB)\n", - sp, BITS_PER_LONG/4, word, (void *)word); - } - } -} - static bool in_entry_code(unsigned long ip) { char *addr = (char *)ip;
@@ -244,7 +202,6 @@ static bool update_stack_state(struct unwind_state *state, addr, addr_p); } - /* Save the original stack pointer for unwind_dump(): */ if (!state->orig_sp) state->orig_sp = frame;
@@ -346,13 +303,17 @@ bool unwind_next_frame(struct unwind_state *state) "WARNING: kernel stack regs at %p in %s:%d has bad 'bp' value %p\n", state->regs, state->task->comm, state->task->pid, next_bp); - unwind_dump(state); + + if (unwind_debug) + unwind_dump(state); } else { printk_deferred_once(KERN_WARNING "WARNING: kernel stack frame pointer at %p in %s:%d has bad value %p\n", state->bp, state->task->comm, state->task->pid, next_bp); - unwind_dump(state); + + if (unwind_debug) + unwind_dump(state); } the_end: state->stack_info.type = STACK_TYPE_UNKNOWN;
diff --git a/arch/x86/kernel/unwind_orc.c b/arch/x86/kernel/unwind_orc.c
index 73f800100066..38265eac41dd 100644
--- a/arch/x86/kernel/unwind_orc.c
+++ b/arch/x86/kernel/unwind_orc.c@@ -13,8 +13,11 @@ #define orc_warn_current(args...) \ ({ \ - if (state->task == current) \ + if (state->task == current) { \ orc_warn(args); \ + if (unwind_debug) \ + unwind_dump(state); \ + } \ }) extern int __start_orc_unwind_ip[];
--
2.29.2