[RFC PATCH 3/3] arm64: stacktrace: Implement reliable stacktrace
Mark Rutland
mark.rutland at arm.com
Tue Oct 13 07:42:30 EDT 2020
On Mon, Oct 12, 2020 at 06:26:05PM +0100, Mark Brown wrote:
> Live patching has a consistency model which requires that the
> architecture provide a reliable stack trace interface which specifically
> indicates that the stack has been fully walked and that it is reliable
> and consistent. This is done by providing arch_stack_walk_reliable(), a
> variant of arch_stack_walk() which should verify that the stack has
> these properties and return an error if not.
>
> The arm64 unwinder is already reasonably thorough in verifying the stack
> as it walks it and reports errors but we additionally check that
> we do not see any kretprobe trampolines on the stack. Since the unwinder
> is able to resolve function graph tracer probes transparently we do not
> reject those.
>
> Signed-off-by: Mark Brown <broonie at kernel.org>
> ---
> arch/arm64/Kconfig | 1 +
> arch/arm64/kernel/stacktrace.c | 42 ++++++++++++++++++++++++++++++++++
> 2 files changed, 43 insertions(+)
>
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index d1ba52e4b976..026f69515a86 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -174,6 +174,7 @@ config ARM64
> select HAVE_FUNCTION_ARG_ACCESS_API
> select HAVE_FUTEX_CMPXCHG if FUTEX
> select MMU_GATHER_RCU_TABLE_FREE
> + select HAVE_RELIABLE_STACKTRACE
> select HAVE_RSEQ
> select HAVE_STACKPROTECTOR
> select HAVE_SYSCALL_TRACEPOINTS
> diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
> index ad20981dfda4..795b2c14481d 100644
> --- a/arch/arm64/kernel/stacktrace.c
> +++ b/arch/arm64/kernel/stacktrace.c
> @@ -14,6 +14,7 @@
> #include <linux/stacktrace.h>
>
> #include <asm/irq.h>
> +#include <asm/kprobes.h>
> #include <asm/pointer_auth.h>
> #include <asm/stack_pointer.h>
> #include <asm/stacktrace.h>
> @@ -212,4 +213,45 @@ void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
> walk_stackframe(task, &frame, consume_entry, cookie);
> }
>
> +/*
> + * This function returns an error if it detects any unreliable features of the
> + * stack. Otherwise it guarantees that the stack trace is reliable.
> + *
> + * If the task is not 'current', the caller *must* ensure the task is inactive.
> + */
Is the caller responsible for pinning a non-current task's stack? e.g.
in dump_backtrace() we do that with try_get_task_stack(). If so, it
might be worth making the comment say "the task is inactive and its
stack is pinned".
> +int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry,
> + void *cookie, struct task_struct *task)
> +{
> + struct stackframe frame;
> +
> + if (task == current)
> + start_backtrace(&frame,
> + (unsigned long)__builtin_frame_address(0),
> + (unsigned long)arch_stack_walk_reliable);
> + else
> + start_backtrace(&frame, thread_saved_fp(task),
> + thread_saved_pc(task));
> +
Codestyle nit: as these spread over multiple lines the if-else clauses
should have braces.
> + while (1) {
> + int ret;
> +
> +#ifdef CONFIG_KPROBES
> + /*
> + * Mark stacktraces with kretprobed functions on them
> + * as unreliable.
> + */
> + if (frame.pc == (unsigned long)kretprobe_trampoline)
> + return -EINVAL;
> +#endif
I'm going to reply separately on this -- I think the check isn't quite
sufficient, and there's a larger semantic problem, so I'll write that up
with the livepatch and arch maintainers on Cc.
Otherwise, (modulo pac stripping) this looks about right to me.
Thanks,
Mark.
> +
> + if (!consume_entry(cookie, frame.pc))
> + return -EINVAL;
> + ret = unwind_frame(task, &frame);
> + if (ret == -ENOENT)
> + return 0;
> + if (ret < 0)
> + return ret;
> + }
> +}
> +
> #endif
> --
> 2.20.1
>
More information about the linux-arm-kernel
mailing list