From: "Madhavan T. Venkataraman" <madvenka@xxxxxxxxxxxxxxxxxxx> The unwinder should check for the presence of various features and conditions that can render the stack trace unreliable. Introduce a function unwind_check_frame() for this purpose. Introduce the first reliability check in unwind_check_frame() - If a return PC is not a valid kernel text address, consider the stack trace unreliable. It could be some generated code. Other reliability checks will be added in the future. If a reliability check fails, it is a non-fatal error. Introduce a new return code, UNWIND_CONTINUE_WITH_RISK, for non-fatal errors. Call unwind_check_frame() from unwind_frame(). Also, call it from start_backtrace() to remove the current assumption that the starting frame is reliable. Signed-off-by: Madhavan T. Venkataraman <madvenka@xxxxxxxxxxxxxxxxxxx> --- arch/arm64/include/asm/stacktrace.h | 4 +++- arch/arm64/kernel/stacktrace.c | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h index 6fcd58553fb1..d1625d55b980 100644 --- a/arch/arm64/include/asm/stacktrace.h +++ b/arch/arm64/include/asm/stacktrace.h @@ -32,6 +32,7 @@ struct stack_info { enum unwind_rc { UNWIND_CONTINUE, /* No errors encountered */ + UNWIND_CONTINUE_WITH_RISK, /* Non-fatal errors encountered */ UNWIND_ABORT, /* Fatal errors encountered */ UNWIND_FINISH, /* End of stack reached successfully */ }; @@ -73,6 +74,7 @@ extern void walk_stackframe(struct task_struct *tsk, struct stackframe *frame, bool (*fn)(void *, unsigned long), void *data); extern void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk, const char *loglvl); +extern enum unwind_rc unwind_check_frame(struct stackframe *frame); DECLARE_PER_CPU(unsigned long *, irq_stack_ptr); @@ -176,7 +178,7 @@ static inline enum unwind_rc start_backtrace(struct stackframe *frame, bitmap_zero(frame->stacks_done, __NR_STACK_TYPES); frame->prev_fp = 0; frame->prev_type = STACK_TYPE_UNKNOWN; - return UNWIND_CONTINUE; + return unwind_check_frame(frame); } #endif /* __ASM_STACKTRACE_H */ diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index e9c2c1fa9dde..ba7b97b119e4 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -18,6 +18,21 @@ #include <asm/stack_pointer.h> #include <asm/stacktrace.h> +/* + * Check the stack frame for conditions that make unwinding unreliable. + */ +enum unwind_rc unwind_check_frame(struct stackframe *frame) +{ + /* + * If the PC is not a known kernel text address, then we cannot + * be sure that a subsequent unwind will be reliable, as we + * don't know that the code follows our unwind requirements. + */ + if (!__kernel_text_address(frame->pc)) + return UNWIND_CONTINUE_WITH_RISK; + return UNWIND_CONTINUE; +} + /* * AArch64 PCS assigns the frame pointer to x29. * @@ -109,7 +124,7 @@ enum unwind_rc notrace unwind_frame(struct task_struct *tsk, frame->pc = ptrauth_strip_insn_pac(frame->pc); - return UNWIND_CONTINUE; + return unwind_check_frame(frame); } NOKPROBE_SYMBOL(unwind_frame); -- 2.25.1