* [PATCH 0/4] x86/unwind: add some unwinder warnings
@ 2016-10-26 15:41 Josh Poimboeuf
2016-10-26 15:41 ` [PATCH 1/4] x86/unwind: warn on bad frame pointer Josh Poimboeuf
` (3 more replies)
0 siblings, 4 replies; 11+ messages in thread
From: Josh Poimboeuf @ 2016-10-26 15:41 UTC (permalink / raw)
To: x86; +Cc: linux-kernel
Detect some stack error conditions in the unwinder and warn about them.
These warnings may help with debugging stack corruption issues.
Josh Poimboeuf (4):
x86/unwind: warn on bad frame pointer
x86/unwind: ensure stack grows down
x86/dumpstack: warn on stack recursion
x86/unwind: detect bad stack return address
arch/x86/kernel/dumpstack_32.c | 5 +++-
arch/x86/kernel/dumpstack_64.c | 5 +++-
arch/x86/kernel/unwind_frame.c | 56 +++++++++++++++++++++++++++++++++++++++---
3 files changed, 61 insertions(+), 5 deletions(-)
--
2.7.4
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/4] x86/unwind: warn on bad frame pointer
2016-10-26 15:41 [PATCH 0/4] x86/unwind: add some unwinder warnings Josh Poimboeuf
@ 2016-10-26 15:41 ` Josh Poimboeuf
2016-10-27 7:37 ` [tip:x86/asm] x86/unwind: Warn " tip-bot for Josh Poimboeuf
2016-10-26 15:41 ` [PATCH 2/4] x86/unwind: ensure stack grows down Josh Poimboeuf
` (2 subsequent siblings)
3 siblings, 1 reply; 11+ messages in thread
From: Josh Poimboeuf @ 2016-10-26 15:41 UTC (permalink / raw)
To: x86; +Cc: linux-kernel
Detect situations in the unwinder where the frame pointer refers to a
bad address, and print an appropriate warning.
Use printk_deferred_once() because the unwinder can be called with the
console lock by lockdep via save_stack_trace().
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
---
arch/x86/kernel/unwind_frame.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kernel/unwind_frame.c b/arch/x86/kernel/unwind_frame.c
index 5795427..9be9a8f 100644
--- a/arch/x86/kernel/unwind_frame.c
+++ b/arch/x86/kernel/unwind_frame.c
@@ -123,8 +123,17 @@ bool unwind_next_frame(struct unwind_state *state)
}
/* make sure the next frame's data is accessible */
- if (!update_stack_state(state, next_frame, next_len))
- return false;
+ if (!update_stack_state(state, next_frame, next_len)) {
+ /*
+ * 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;
+ }
+
/* move to the next frame */
if (regs) {
state->regs = regs;
@@ -136,6 +145,11 @@ bool unwind_next_frame(struct unwind_state *state)
return true;
+bad_address:
+ 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);
the_end:
state->stack_info.type = STACK_TYPE_UNKNOWN;
return false;
--
2.7.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/4] x86/unwind: ensure stack grows down
2016-10-26 15:41 [PATCH 0/4] x86/unwind: add some unwinder warnings Josh Poimboeuf
2016-10-26 15:41 ` [PATCH 1/4] x86/unwind: warn on bad frame pointer Josh Poimboeuf
@ 2016-10-26 15:41 ` Josh Poimboeuf
2016-10-27 6:30 ` Ingo Molnar
2016-10-26 15:41 ` [PATCH 3/4] x86/dumpstack: warn on stack recursion Josh Poimboeuf
2016-10-26 15:41 ` [PATCH 4/4] x86/unwind: detect bad stack return address Josh Poimboeuf
3 siblings, 1 reply; 11+ messages in thread
From: Josh Poimboeuf @ 2016-10-26 15:41 UTC (permalink / raw)
To: x86; +Cc: linux-kernel
Add a sanity check to ensure the stack only grows down, and print a
warning if the check fails.
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
---
arch/x86/kernel/unwind_frame.c | 36 ++++++++++++++++++++++++++++++++----
1 file changed, 32 insertions(+), 4 deletions(-)
diff --git a/arch/x86/kernel/unwind_frame.c b/arch/x86/kernel/unwind_frame.c
index 9be9a8f..0d8d2f2 100644
--- a/arch/x86/kernel/unwind_frame.c
+++ b/arch/x86/kernel/unwind_frame.c
@@ -24,6 +24,15 @@ unsigned long unwind_get_return_address(struct unwind_state *state)
}
EXPORT_SYMBOL_GPL(unwind_get_return_address);
+static size_t regs_size(struct pt_regs *regs)
+{
+ /* x86_32 regs from kernel mode are two words shorter */
+ if (IS_ENABLED(CONFIG_X86_32) && !user_mode(regs))
+ return sizeof(*regs) - (2*sizeof(long));
+
+ return sizeof(*regs);
+}
+
static bool is_last_task_frame(struct unwind_state *state)
{
unsigned long bp = (unsigned long)state->bp;
@@ -71,6 +80,7 @@ bool unwind_next_frame(struct unwind_state *state)
struct pt_regs *regs;
unsigned long *next_bp, *next_frame;
size_t next_len;
+ enum stack_type prev_type = state->stack_info.type;
if (unwind_done(state))
return false;
@@ -134,6 +144,18 @@ bool unwind_next_frame(struct unwind_state *state)
goto bad_address;
}
+ /* make sure it only unwinds up and doesn't overlap the last frame */
+ if (state->stack_info.type == prev_type) {
+ if (state->regs &&
+ (void *)next_frame < (void *)state->regs +
+ regs_size(state->regs))
+ goto bad_address;
+
+ if (state->bp &&
+ (void *)next_frame < (void *)state->bp + FRAME_HEADER_SIZE)
+ goto bad_address;
+ }
+
/* move to the next frame */
if (regs) {
state->regs = regs;
@@ -146,10 +168,16 @@ bool unwind_next_frame(struct unwind_state *state)
return true;
bad_address:
- 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);
+ if (state->regs)
+ printk_deferred_once(KERN_WARNING
+ "WARNING: kernel stack regs at %p in %s:%d has bad 'bp' value %p\n",
+ state->regs, state->task->comm,
+ state->task->pid, next_frame);
+ 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_frame);
the_end:
state->stack_info.type = STACK_TYPE_UNKNOWN;
return false;
--
2.7.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 3/4] x86/dumpstack: warn on stack recursion
2016-10-26 15:41 [PATCH 0/4] x86/unwind: add some unwinder warnings Josh Poimboeuf
2016-10-26 15:41 ` [PATCH 1/4] x86/unwind: warn on bad frame pointer Josh Poimboeuf
2016-10-26 15:41 ` [PATCH 2/4] x86/unwind: ensure stack grows down Josh Poimboeuf
@ 2016-10-26 15:41 ` Josh Poimboeuf
2016-10-27 7:38 ` [tip:x86/asm] x86/dumpstack: Warn " tip-bot for Josh Poimboeuf
2016-10-26 15:41 ` [PATCH 4/4] x86/unwind: detect bad stack return address Josh Poimboeuf
3 siblings, 1 reply; 11+ messages in thread
From: Josh Poimboeuf @ 2016-10-26 15:41 UTC (permalink / raw)
To: x86; +Cc: linux-kernel
Print a warning if stack recursion is detected.
Use printk_deferred_once() because the unwinder can be called with the
console lock by lockdep via save_stack_trace().
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
---
arch/x86/kernel/dumpstack_32.c | 5 ++++-
arch/x86/kernel/dumpstack_64.c | 5 ++++-
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
index 90cf460..99ac8d2 100644
--- a/arch/x86/kernel/dumpstack_32.c
+++ b/arch/x86/kernel/dumpstack_32.c
@@ -109,8 +109,11 @@ int get_stack_info(unsigned long *stack, struct task_struct *task,
* just break out and report an unknown stack type.
*/
if (visit_mask) {
- if (*visit_mask & (1UL << info->type))
+ if (*visit_mask & (1UL << info->type)) {
+ printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n",
+ info->type);
goto unknown;
+ }
*visit_mask |= 1UL << info->type;
}
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index 310abf4..26e6e83 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -128,8 +128,11 @@ int get_stack_info(unsigned long *stack, struct task_struct *task,
* just break out and report an unknown stack type.
*/
if (visit_mask) {
- if (*visit_mask & (1UL << info->type))
+ if (*visit_mask & (1UL << info->type)) {
+ printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n",
+ info->type);
goto unknown;
+ }
*visit_mask |= 1UL << info->type;
}
--
2.7.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 4/4] x86/unwind: detect bad stack return address
2016-10-26 15:41 [PATCH 0/4] x86/unwind: add some unwinder warnings Josh Poimboeuf
` (2 preceding siblings ...)
2016-10-26 15:41 ` [PATCH 3/4] x86/dumpstack: warn on stack recursion Josh Poimboeuf
@ 2016-10-26 15:41 ` Josh Poimboeuf
2016-10-27 7:38 ` [tip:x86/asm] x86/unwind: Detect " tip-bot for Josh Poimboeuf
3 siblings, 1 reply; 11+ messages in thread
From: Josh Poimboeuf @ 2016-10-26 15:41 UTC (permalink / raw)
To: x86; +Cc: linux-kernel
If __kernel_text_address() doesn't recognize a return address on the
stack, it probably means that it's some generated code which
__kernel_text_address() doesn't know about yet.
Otherwise there's probably some stack corruption.
Either way, warn about it.
Use printk_deferred_once() because the unwinder can be called with the
console lock by lockdep via save_stack_trace().
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
---
arch/x86/kernel/unwind_frame.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/arch/x86/kernel/unwind_frame.c b/arch/x86/kernel/unwind_frame.c
index 0d8d2f2..b6fcf44 100644
--- a/arch/x86/kernel/unwind_frame.c
+++ b/arch/x86/kernel/unwind_frame.c
@@ -20,7 +20,15 @@ unsigned long unwind_get_return_address(struct unwind_state *state)
addr = ftrace_graph_ret_addr(state->task, &state->graph_idx, *addr_p,
addr_p);
- return __kernel_text_address(addr) ? addr : 0;
+ if (!__kernel_text_address(addr)) {
+ printk_deferred_once(KERN_WARNING
+ "WARNING: unrecognized kernel stack return address %p at %p in %s:%d\n",
+ (void *)addr, addr_p, state->task->comm,
+ state->task->pid);
+ return 0;
+ }
+
+ return addr;
}
EXPORT_SYMBOL_GPL(unwind_get_return_address);
--
2.7.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 2/4] x86/unwind: ensure stack grows down
2016-10-26 15:41 ` [PATCH 2/4] x86/unwind: ensure stack grows down Josh Poimboeuf
@ 2016-10-27 6:30 ` Ingo Molnar
2016-10-27 13:10 ` [PATCH v2] " Josh Poimboeuf
0 siblings, 1 reply; 11+ messages in thread
From: Ingo Molnar @ 2016-10-27 6:30 UTC (permalink / raw)
To: Josh Poimboeuf; +Cc: x86, linux-kernel
* Josh Poimboeuf <jpoimboe@redhat.com> wrote:
> Add a sanity check to ensure the stack only grows down, and print a
> warning if the check fails.
>
> Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
> ---
> arch/x86/kernel/unwind_frame.c | 36 ++++++++++++++++++++++++++++++++----
> 1 file changed, 32 insertions(+), 4 deletions(-)
>
> diff --git a/arch/x86/kernel/unwind_frame.c b/arch/x86/kernel/unwind_frame.c
> index 9be9a8f..0d8d2f2 100644
> --- a/arch/x86/kernel/unwind_frame.c
> +++ b/arch/x86/kernel/unwind_frame.c
> @@ -24,6 +24,15 @@ unsigned long unwind_get_return_address(struct unwind_state *state)
> }
> EXPORT_SYMBOL_GPL(unwind_get_return_address);
>
> +static size_t regs_size(struct pt_regs *regs)
> +{
> + /* x86_32 regs from kernel mode are two words shorter */
> + if (IS_ENABLED(CONFIG_X86_32) && !user_mode(regs))
> + return sizeof(*regs) - (2*sizeof(long));
Unnecessary parentheses.
> +
> + return sizeof(*regs);
> +}
> +
> static bool is_last_task_frame(struct unwind_state *state)
> {
> unsigned long bp = (unsigned long)state->bp;
> @@ -71,6 +80,7 @@ bool unwind_next_frame(struct unwind_state *state)
> struct pt_regs *regs;
> unsigned long *next_bp, *next_frame;
> size_t next_len;
> + enum stack_type prev_type = state->stack_info.type;
>
> if (unwind_done(state))
> return false;
> @@ -134,6 +144,18 @@ bool unwind_next_frame(struct unwind_state *state)
> goto bad_address;
> }
>
> + /* make sure it only unwinds up and doesn't overlap the last frame */
Please capitalize comments - and if the comment refers to a control block please
also add ':', i.e. something like:
/* Make sure it only unwinds up and doesn't overlap the last frame: */
This also applies to other places in this patch series.
> + if (state->stack_info.type == prev_type) {
> + if (state->regs &&
> + (void *)next_frame < (void *)state->regs +
> + regs_size(state->regs))
No line breaks that make the code worse please.
> + goto bad_address;
> +
> + if (state->bp &&
> + (void *)next_frame < (void *)state->bp + FRAME_HEADER_SIZE)
Ditto.
> + goto bad_address;
> + }
> +
> /* move to the next frame */
> if (regs) {
> state->regs = regs;
> @@ -146,10 +168,16 @@ bool unwind_next_frame(struct unwind_state *state)
> return true;
>
> bad_address:
> - 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);
> + if (state->regs)
> + printk_deferred_once(KERN_WARNING
> + "WARNING: kernel stack regs at %p in %s:%d has bad 'bp' value %p\n",
> + state->regs, state->task->comm,
> + state->task->pid, next_frame);
> + 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_frame);
Multi-line statements should have curly braces.
Thanks,
Ingo
^ permalink raw reply [flat|nested] 11+ messages in thread
* [tip:x86/asm] x86/unwind: Warn on bad frame pointer
2016-10-26 15:41 ` [PATCH 1/4] x86/unwind: warn on bad frame pointer Josh Poimboeuf
@ 2016-10-27 7:37 ` tip-bot for Josh Poimboeuf
0 siblings, 0 replies; 11+ messages in thread
From: tip-bot for Josh Poimboeuf @ 2016-10-27 7:37 UTC (permalink / raw)
To: linux-tip-commits
Cc: torvalds, jpoimboe, tglx, dvlasenk, luto, peterz, linux-kernel,
brgerst, mingo, hpa, bp
Commit-ID: c32c47c68a0ae701088c5b2c3798856ed16746ae
Gitweb: http://git.kernel.org/tip/c32c47c68a0ae701088c5b2c3798856ed16746ae
Author: Josh Poimboeuf <jpoimboe@redhat.com>
AuthorDate: Wed, 26 Oct 2016 10:41:48 -0500
Committer: Ingo Molnar <mingo@kernel.org>
CommitDate: Thu, 27 Oct 2016 08:32:37 +0200
x86/unwind: Warn on bad frame pointer
Detect situations in the unwinder where the frame pointer refers to a
bad address, and print an appropriate warning.
Use printk_deferred_once() because the unwinder can be called with the
console lock by lockdep via save_stack_trace().
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
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>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/03c888f6f7414d54fa56b393ea25482be6899b5f.1477496147.git.jpoimboe@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
---
arch/x86/kernel/unwind_frame.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kernel/unwind_frame.c b/arch/x86/kernel/unwind_frame.c
index 5795427..9be9a8f 100644
--- a/arch/x86/kernel/unwind_frame.c
+++ b/arch/x86/kernel/unwind_frame.c
@@ -123,8 +123,17 @@ bool unwind_next_frame(struct unwind_state *state)
}
/* make sure the next frame's data is accessible */
- if (!update_stack_state(state, next_frame, next_len))
- return false;
+ if (!update_stack_state(state, next_frame, next_len)) {
+ /*
+ * 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;
+ }
+
/* move to the next frame */
if (regs) {
state->regs = regs;
@@ -136,6 +145,11 @@ bool unwind_next_frame(struct unwind_state *state)
return true;
+bad_address:
+ 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);
the_end:
state->stack_info.type = STACK_TYPE_UNKNOWN;
return false;
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [tip:x86/asm] x86/dumpstack: Warn on stack recursion
2016-10-26 15:41 ` [PATCH 3/4] x86/dumpstack: warn on stack recursion Josh Poimboeuf
@ 2016-10-27 7:38 ` tip-bot for Josh Poimboeuf
0 siblings, 0 replies; 11+ messages in thread
From: tip-bot for Josh Poimboeuf @ 2016-10-27 7:38 UTC (permalink / raw)
To: linux-tip-commits
Cc: torvalds, bp, tglx, mingo, luto, peterz, jpoimboe, linux-kernel,
brgerst, dvlasenk, hpa
Commit-ID: 0d2b8579add41e08aa1110da864f1071d58e6048
Gitweb: http://git.kernel.org/tip/0d2b8579add41e08aa1110da864f1071d58e6048
Author: Josh Poimboeuf <jpoimboe@redhat.com>
AuthorDate: Wed, 26 Oct 2016 10:41:50 -0500
Committer: Ingo Molnar <mingo@kernel.org>
CommitDate: Thu, 27 Oct 2016 08:32:38 +0200
x86/dumpstack: Warn on stack recursion
Print a warning if stack recursion is detected.
Use printk_deferred_once() because the unwinder can be called with the
console lock by lockdep via save_stack_trace().
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
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>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/def18247aafaab480844484398e793f552b79bda.1477496147.git.jpoimboe@redhat.com
[ Unbroke the lines. ]
Signed-off-by: Ingo Molnar <mingo@kernel.org>
---
arch/x86/kernel/dumpstack_32.c | 4 +++-
arch/x86/kernel/dumpstack_64.c | 4 +++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c
index 90cf460..d7d20999 100644
--- a/arch/x86/kernel/dumpstack_32.c
+++ b/arch/x86/kernel/dumpstack_32.c
@@ -109,8 +109,10 @@ recursion_check:
* just break out and report an unknown stack type.
*/
if (visit_mask) {
- if (*visit_mask & (1UL << info->type))
+ if (*visit_mask & (1UL << info->type)) {
+ printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type);
goto unknown;
+ }
*visit_mask |= 1UL << info->type;
}
diff --git a/arch/x86/kernel/dumpstack_64.c b/arch/x86/kernel/dumpstack_64.c
index 310abf4..ab0f8b9 100644
--- a/arch/x86/kernel/dumpstack_64.c
+++ b/arch/x86/kernel/dumpstack_64.c
@@ -128,8 +128,10 @@ recursion_check:
* just break out and report an unknown stack type.
*/
if (visit_mask) {
- if (*visit_mask & (1UL << info->type))
+ if (*visit_mask & (1UL << info->type)) {
+ printk_deferred_once(KERN_WARNING "WARNING: stack recursion on stack type %d\n", info->type);
goto unknown;
+ }
*visit_mask |= 1UL << info->type;
}
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [tip:x86/asm] x86/unwind: Detect bad stack return address
2016-10-26 15:41 ` [PATCH 4/4] x86/unwind: detect bad stack return address Josh Poimboeuf
@ 2016-10-27 7:38 ` tip-bot for Josh Poimboeuf
0 siblings, 0 replies; 11+ messages in thread
From: tip-bot for Josh Poimboeuf @ 2016-10-27 7:38 UTC (permalink / raw)
To: linux-tip-commits
Cc: torvalds, luto, hpa, brgerst, linux-kernel, peterz, bp, dvlasenk,
tglx, mingo, jpoimboe
Commit-ID: b6959a362177053c1c90db6dc1af25b6bddd8548
Gitweb: http://git.kernel.org/tip/b6959a362177053c1c90db6dc1af25b6bddd8548
Author: Josh Poimboeuf <jpoimboe@redhat.com>
AuthorDate: Wed, 26 Oct 2016 10:41:51 -0500
Committer: Ingo Molnar <mingo@kernel.org>
CommitDate: Thu, 27 Oct 2016 08:32:38 +0200
x86/unwind: Detect bad stack return address
If __kernel_text_address() doesn't recognize a return address on the
stack, it probably means that it's some generated code which
__kernel_text_address() doesn't know about yet.
Otherwise there's probably some stack corruption.
Either way, warn about it.
Use printk_deferred_once() because the unwinder can be called with the
console lock by lockdep via save_stack_trace().
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
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>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/2d897898f324e275943b590d160b55e482bba65f.1477496147.git.jpoimboe@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
---
arch/x86/kernel/unwind_frame.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/arch/x86/kernel/unwind_frame.c b/arch/x86/kernel/unwind_frame.c
index 9be9a8f..5639db6 100644
--- a/arch/x86/kernel/unwind_frame.c
+++ b/arch/x86/kernel/unwind_frame.c
@@ -20,7 +20,15 @@ unsigned long unwind_get_return_address(struct unwind_state *state)
addr = ftrace_graph_ret_addr(state->task, &state->graph_idx, *addr_p,
addr_p);
- return __kernel_text_address(addr) ? addr : 0;
+ if (!__kernel_text_address(addr)) {
+ printk_deferred_once(KERN_WARNING
+ "WARNING: unrecognized kernel stack return address %p at %p in %s:%d\n",
+ (void *)addr, addr_p, state->task->comm,
+ state->task->pid);
+ return 0;
+ }
+
+ return addr;
}
EXPORT_SYMBOL_GPL(unwind_get_return_address);
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v2] x86/unwind: ensure stack grows down
2016-10-27 6:30 ` Ingo Molnar
@ 2016-10-27 13:10 ` Josh Poimboeuf
2016-10-28 6:49 ` [tip:x86/asm] x86/unwind: Ensure " tip-bot for Josh Poimboeuf
0 siblings, 1 reply; 11+ messages in thread
From: Josh Poimboeuf @ 2016-10-27 13:10 UTC (permalink / raw)
To: Ingo Molnar; +Cc: x86, linux-kernel
Add a sanity check to ensure the stack only grows down, and print a
warning if the check fails.
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
---
arch/x86/kernel/unwind_frame.c | 34 ++++++++++++++++++++++++++++++----
1 file changed, 30 insertions(+), 4 deletions(-)
diff --git a/arch/x86/kernel/unwind_frame.c b/arch/x86/kernel/unwind_frame.c
index 5639db6..fe4d387 100644
--- a/arch/x86/kernel/unwind_frame.c
+++ b/arch/x86/kernel/unwind_frame.c
@@ -32,6 +32,15 @@ unsigned long unwind_get_return_address(struct unwind_state *state)
}
EXPORT_SYMBOL_GPL(unwind_get_return_address);
+static size_t regs_size(struct pt_regs *regs)
+{
+ /* x86_32 regs from kernel mode are two words shorter */
+ if (IS_ENABLED(CONFIG_X86_32) && !user_mode(regs))
+ return sizeof(*regs) - 2*sizeof(long);
+
+ return sizeof(*regs);
+}
+
static bool is_last_task_frame(struct unwind_state *state)
{
unsigned long bp = (unsigned long)state->bp;
@@ -79,6 +88,7 @@ bool unwind_next_frame(struct unwind_state *state)
struct pt_regs *regs;
unsigned long *next_bp, *next_frame;
size_t next_len;
+ enum stack_type prev_type = state->stack_info.type;
if (unwind_done(state))
return false;
@@ -142,6 +152,15 @@ bool unwind_next_frame(struct unwind_state *state)
goto bad_address;
}
+ /* Make sure it only unwinds up and doesn't overlap the last frame: */
+ if (state->stack_info.type == prev_type) {
+ if (state->regs && (void *)next_frame < (void *)state->regs + regs_size(state->regs))
+ goto bad_address;
+
+ if (state->bp && (void *)next_frame < (void *)state->bp + FRAME_HEADER_SIZE)
+ goto bad_address;
+ }
+
/* move to the next frame */
if (regs) {
state->regs = regs;
@@ -154,10 +173,17 @@ bool unwind_next_frame(struct unwind_state *state)
return true;
bad_address:
- 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);
+ if (state->regs) {
+ printk_deferred_once(KERN_WARNING
+ "WARNING: kernel stack regs at %p in %s:%d has bad 'bp' value %p\n",
+ state->regs, state->task->comm,
+ state->task->pid, next_frame);
+ } 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_frame);
+ }
the_end:
state->stack_info.type = STACK_TYPE_UNKNOWN;
return false;
--
2.7.4
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [tip:x86/asm] x86/unwind: Ensure stack grows down
2016-10-27 13:10 ` [PATCH v2] " Josh Poimboeuf
@ 2016-10-28 6:49 ` tip-bot for Josh Poimboeuf
0 siblings, 0 replies; 11+ messages in thread
From: tip-bot for Josh Poimboeuf @ 2016-10-28 6:49 UTC (permalink / raw)
To: linux-tip-commits
Cc: torvalds, luto, dvlasenk, peterz, bp, linux-kernel, jpoimboe,
brgerst, mingo, hpa, tglx
Commit-ID: 24d86f59093b0bcb3756cdf47f2db10ff4e90dbb
Gitweb: http://git.kernel.org/tip/24d86f59093b0bcb3756cdf47f2db10ff4e90dbb
Author: Josh Poimboeuf <jpoimboe@redhat.com>
AuthorDate: Thu, 27 Oct 2016 08:10:58 -0500
Committer: Ingo Molnar <mingo@kernel.org>
CommitDate: Fri, 28 Oct 2016 08:16:45 +0200
x86/unwind: Ensure stack grows down
Add a sanity check to ensure the stack only grows down, and print a
warning if the check fails.
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
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>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20161027131058.tpdffwlqipv7pcd6@treble
Signed-off-by: Ingo Molnar <mingo@kernel.org>
---
arch/x86/kernel/unwind_frame.c | 34 ++++++++++++++++++++++++++++++----
1 file changed, 30 insertions(+), 4 deletions(-)
diff --git a/arch/x86/kernel/unwind_frame.c b/arch/x86/kernel/unwind_frame.c
index 5639db6..ea7b7f9 100644
--- a/arch/x86/kernel/unwind_frame.c
+++ b/arch/x86/kernel/unwind_frame.c
@@ -32,6 +32,15 @@ unsigned long unwind_get_return_address(struct unwind_state *state)
}
EXPORT_SYMBOL_GPL(unwind_get_return_address);
+static size_t regs_size(struct pt_regs *regs)
+{
+ /* x86_32 regs from kernel mode are two words shorter: */
+ if (IS_ENABLED(CONFIG_X86_32) && !user_mode(regs))
+ return sizeof(*regs) - 2*sizeof(long);
+
+ return sizeof(*regs);
+}
+
static bool is_last_task_frame(struct unwind_state *state)
{
unsigned long bp = (unsigned long)state->bp;
@@ -79,6 +88,7 @@ bool unwind_next_frame(struct unwind_state *state)
struct pt_regs *regs;
unsigned long *next_bp, *next_frame;
size_t next_len;
+ enum stack_type prev_type = state->stack_info.type;
if (unwind_done(state))
return false;
@@ -142,6 +152,15 @@ bool unwind_next_frame(struct unwind_state *state)
goto bad_address;
}
+ /* Make sure it only unwinds up and doesn't overlap the last frame: */
+ if (state->stack_info.type == prev_type) {
+ if (state->regs && (void *)next_frame < (void *)state->regs + regs_size(state->regs))
+ goto bad_address;
+
+ if (state->bp && (void *)next_frame < (void *)state->bp + FRAME_HEADER_SIZE)
+ goto bad_address;
+ }
+
/* move to the next frame */
if (regs) {
state->regs = regs;
@@ -154,10 +173,17 @@ bool unwind_next_frame(struct unwind_state *state)
return true;
bad_address:
- 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);
+ if (state->regs) {
+ printk_deferred_once(KERN_WARNING
+ "WARNING: kernel stack regs at %p in %s:%d has bad 'bp' value %p\n",
+ state->regs, state->task->comm,
+ state->task->pid, next_frame);
+ } 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_frame);
+ }
the_end:
state->stack_info.type = STACK_TYPE_UNKNOWN;
return false;
^ permalink raw reply related [flat|nested] 11+ messages in thread
end of thread, other threads:[~2016-10-28 6:50 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-26 15:41 [PATCH 0/4] x86/unwind: add some unwinder warnings Josh Poimboeuf
2016-10-26 15:41 ` [PATCH 1/4] x86/unwind: warn on bad frame pointer Josh Poimboeuf
2016-10-27 7:37 ` [tip:x86/asm] x86/unwind: Warn " tip-bot for Josh Poimboeuf
2016-10-26 15:41 ` [PATCH 2/4] x86/unwind: ensure stack grows down Josh Poimboeuf
2016-10-27 6:30 ` Ingo Molnar
2016-10-27 13:10 ` [PATCH v2] " Josh Poimboeuf
2016-10-28 6:49 ` [tip:x86/asm] x86/unwind: Ensure " tip-bot for Josh Poimboeuf
2016-10-26 15:41 ` [PATCH 3/4] x86/dumpstack: warn on stack recursion Josh Poimboeuf
2016-10-27 7:38 ` [tip:x86/asm] x86/dumpstack: Warn " tip-bot for Josh Poimboeuf
2016-10-26 15:41 ` [PATCH 4/4] x86/unwind: detect bad stack return address Josh Poimboeuf
2016-10-27 7:38 ` [tip:x86/asm] x86/unwind: Detect " tip-bot for Josh Poimboeuf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).