diff options
author | Mark Rutland <mark.rutland@arm.com> | 2017-08-01 18:51:15 +0100 |
---|---|---|
committer | Mark Rutland <mark.rutland@arm.com> | 2017-08-15 18:36:12 +0100 |
commit | 12964443e8d1914010f9269f9f9abc4e122bc6ca (patch) | |
tree | d111b3b683530290cc4d65992456b68167916a20 | |
parent | e3067861ba6650a566a6273738c23c956ad55c02 (diff) | |
download | linux-12964443e8d1914010f9269f9f9abc4e122bc6ca.tar.bz2 |
arm64: add on_accessible_stack()
Both unwind_frame() and dump_backtrace() try to check whether a stack
address is sane to access, with very similar logic. Both will need
updating in order to handle overflow stacks.
Factor out this logic into a helper, so that we can avoid further
duplication when we add overflow stacks.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Will Deacon <will.deacon@arm.com>
Tested-by: Laura Abbott <labbott@redhat.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: James Morse <james.morse@arm.com>
-rw-r--r-- | arch/arm64/include/asm/stacktrace.h | 16 | ||||
-rw-r--r-- | arch/arm64/kernel/stacktrace.c | 7 | ||||
-rw-r--r-- | arch/arm64/kernel/traps.c | 3 |
3 files changed, 18 insertions, 8 deletions
diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h index 4c68d8a81988..92ddb6d25cf3 100644 --- a/arch/arm64/include/asm/stacktrace.h +++ b/arch/arm64/include/asm/stacktrace.h @@ -57,4 +57,20 @@ static inline bool on_task_stack(struct task_struct *tsk, unsigned long sp) return (low <= sp && sp < high); } +/* + * We can only safely access per-cpu stacks from current in a non-preemptible + * context. + */ +static inline bool on_accessible_stack(struct task_struct *tsk, unsigned long sp) +{ + if (on_task_stack(tsk, sp)) + return true; + if (tsk != current || preemptible()) + return false; + if (on_irq_stack(sp)) + return true; + + return false; +} + #endif /* __ASM_STACKTRACE_H */ diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 35588caad9d0..3144584617e7 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -50,12 +50,7 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame) if (!tsk) tsk = current; - /* - * Switching between stacks is valid when tracing current and in - * non-preemptible context. - */ - if (!(tsk == current && !preemptible() && on_irq_stack(fp)) && - !on_task_stack(tsk, fp)) + if (!on_accessible_stack(tsk, fp)) return -EINVAL; frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp)); diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 9633773ca42c..d01c5988354b 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -193,8 +193,7 @@ void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) if (in_entry_text(frame.pc)) { stack = frame.fp - offsetof(struct pt_regs, stackframe); - if (on_task_stack(tsk, stack) || - (tsk == current && !preemptible() && on_irq_stack(stack))) + if (on_accessible_stack(tsk, stack)) dump_mem("", "Exception stack", stack, stack + sizeof(struct pt_regs)); } |