Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1543453 > unrolled thread
| Started by | Petr Mladek <pmladek@suse.com> |
|---|---|
| First post | 2016-12-16 14:10 +0100 |
| Last post | 2016-12-16 23:20 +0100 |
| Articles | 2 — 2 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: [PATCH v3 01/15] stacktrace/x86: add function for detecting reliable stack traces Petr Mladek <pmladek@suse.com> - 2016-12-16 14:10 +0100
Re: [PATCH v3 01/15] stacktrace/x86: add function for detecting reliable stack traces Josh Poimboeuf <jpoimboe@redhat.com> - 2016-12-16 23:20 +0100
| From | Petr Mladek <pmladek@suse.com> |
|---|---|
| Date | 2016-12-16 14:10 +0100 |
| Subject | Re: [PATCH v3 01/15] stacktrace/x86: add function for detecting reliable stack traces |
| Message-ID | <sP0qS-42X-15@gated-at.bofh.it> |
On Thu 2016-12-08 12:08:26, Josh Poimboeuf wrote:
> For live patching and possibly other use cases, a stack trace is only
> useful if it can be assured that it's completely reliable. Add a new
> save_stack_trace_tsk_reliable() function to achieve that.
>
> Scenarios which indicate that a stack trace may be unreliable:
>
> - running task
It seems that this has to be enforced by save_stack_trace_tsk_reliable()
caller. It should be mentioned in the function description.
> - interrupt stack
I guess that it is detected by saved regs on the stack. And it covers
also dynamic changes like kprobes. Do I get it correctly, please?
What about ftrace? Is ftrace without regs safe and detected?
> - preemption
I wonder if some very active kthreads might almost always be
preempted using irq in preemptive kernel. Then they block
the conversion with the non-reliable stacks. Have you noticed
such problems, please?
> - corrupted stack data
> - stack grows the wrong way
This is detected in unwind_next_frame() and passed via state->error.
Am I right?
> - stack walk doesn't reach the bottom
> - user didn't provide a large enough entries array
>
> Also add CONFIG_HAVE_RELIABLE_STACKTRACE so arch-independent code can
> determine at build time whether the function is implemented.
>
> diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c
> index 0653788..3e0cf5e 100644
> --- a/arch/x86/kernel/stacktrace.c
> +++ b/arch/x86/kernel/stacktrace.c
> @@ -74,6 +74,64 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
> }
> EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
>
> +#ifdef CONFIG_HAVE_RELIABLE_STACKTRACE
> +static int __save_stack_trace_reliable(struct stack_trace *trace,
> + struct task_struct *task)
> +{
> + struct unwind_state state;
> + struct pt_regs *regs;
> + unsigned long addr;
> +
> + for (unwind_start(&state, task, NULL, NULL); !unwind_done(&state);
> + unwind_next_frame(&state)) {
> +
> + regs = unwind_get_entry_regs(&state);
> + if (regs) {
> + /*
> + * Preemption and page faults on the stack can make
> + * frame pointers unreliable.
> + */
> + if (!user_mode(regs))
> + return -1;
By other words, it we find regs on the stack, it almost always mean
a non-reliable stack. The only exception is when we are in the
userspace mode. Do I get it correctly, please?
> +
> + /*
> + * This frame contains the (user mode) pt_regs at the
> + * end of the stack. Finish the unwind.
> + */
> + unwind_next_frame(&state);
> + break;
> + }
> +
> + addr = unwind_get_return_address(&state);
> + if (!addr || save_stack_address(trace, addr, false))
> + return -1;
> + }
> +
> + if (!unwind_done(&state) || unwind_error(&state))
> + return -1;
> +
> + if (trace->nr_entries < trace->max_entries)
> + trace->entries[trace->nr_entries++] = ULONG_MAX;
> +
> + return 0;
> +}
Great work! I am surprised that it looks so straightforward.
I still have to think and investigate it more. But it looks
very promissing.
Best Regards,
Petr
[toc] | [next] | [standalone]
| From | Josh Poimboeuf <jpoimboe@redhat.com> |
|---|---|
| Date | 2016-12-16 23:20 +0100 |
| Message-ID | <sP918-11E-31@gated-at.bofh.it> |
| In reply to | #1543453 |
On Fri, Dec 16, 2016 at 02:07:39PM +0100, Petr Mladek wrote:
> On Thu 2016-12-08 12:08:26, Josh Poimboeuf wrote:
> > For live patching and possibly other use cases, a stack trace is only
> > useful if it can be assured that it's completely reliable. Add a new
> > save_stack_trace_tsk_reliable() function to achieve that.
> >
> > Scenarios which indicate that a stack trace may be unreliable:
> >
> > - running task
>
> It seems that this has to be enforced by save_stack_trace_tsk_reliable()
> caller. It should be mentioned in the function description.
Agreed.
> > - interrupt stack
>
> I guess that it is detected by saved regs on the stack. And it covers
> also dynamic changes like kprobes. Do I get it correctly, please?
Right.
> What about ftrace? Is ftrace without regs safe and detected?
Yes, it's safe because the mcount code does the right thing with respect
to frame pointers. See save_mcount_regs().
> > - preemption
>
> I wonder if some very active kthreads might almost always be
> preempted using irq in preemptive kernel. Then they block
> the conversion with the non-reliable stacks. Have you noticed
> such problems, please?
I haven't seen such a case and I think it would be quite rare for a
kthread to be CPU-bound like that.
> > - corrupted stack data
> > - stack grows the wrong way
>
> This is detected in unwind_next_frame() and passed via state->error.
> Am I right?
Right. I'll add more details to the commit message for all of these.
>
>
> > - stack walk doesn't reach the bottom
> > - user didn't provide a large enough entries array
> >
> > Also add CONFIG_HAVE_RELIABLE_STACKTRACE so arch-independent code can
> > determine at build time whether the function is implemented.
> >
> > diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c
> > index 0653788..3e0cf5e 100644
> > --- a/arch/x86/kernel/stacktrace.c
> > +++ b/arch/x86/kernel/stacktrace.c
> > @@ -74,6 +74,64 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
> > }
> > EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
> >
> > +#ifdef CONFIG_HAVE_RELIABLE_STACKTRACE
> > +static int __save_stack_trace_reliable(struct stack_trace *trace,
> > + struct task_struct *task)
> > +{
> > + struct unwind_state state;
> > + struct pt_regs *regs;
> > + unsigned long addr;
> > +
> > + for (unwind_start(&state, task, NULL, NULL); !unwind_done(&state);
> > + unwind_next_frame(&state)) {
> > +
> > + regs = unwind_get_entry_regs(&state);
> > + if (regs) {
> > + /*
> > + * Preemption and page faults on the stack can make
> > + * frame pointers unreliable.
> > + */
> > + if (!user_mode(regs))
> > + return -1;
>
> By other words, it we find regs on the stack, it almost always mean
> a non-reliable stack. The only exception is when we are in the
> userspace mode. Do I get it correctly, please?
Right.
> > +
> > + /*
> > + * This frame contains the (user mode) pt_regs at the
> > + * end of the stack. Finish the unwind.
> > + */
> > + unwind_next_frame(&state);
> > + break;
> > + }
> > +
> > + addr = unwind_get_return_address(&state);
> > + if (!addr || save_stack_address(trace, addr, false))
> > + return -1;
> > + }
> > +
> > + if (!unwind_done(&state) || unwind_error(&state))
> > + return -1;
> > +
> > + if (trace->nr_entries < trace->max_entries)
> > + trace->entries[trace->nr_entries++] = ULONG_MAX;
> > +
> > + return 0;
> > +}
>
> Great work! I am surprised that it looks so straightforward.
>
> I still have to think and investigate it more. But it looks
> very promissing.
>
> Best Regards,
> Petr
--
Josh
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web