[PATCH 1/1] arm: get task_stack reference before dump_backtrace

From: Maninder Singh

Date: Thu Mar 05 2026 - 02:06:12 EST


With Support of THREAD_INFO_IN_TASK, stack of task can be
freed earlier than task (even if task's reference is taken),
and it needs separate reference with try_get_task_stack()
before using the stack.
Otherwise if someone calls show_stack() for task, it can oops
the kernel like below: (Tried with normal race of show_stack when
task still exists, but its stack is freed)

8<--- cut here ---
Unable to handle kernel paging request at virtual address f8aebec4 when read
[f8aebec4] *pgd=83c2c811, *pte=00000000, *ppte=00000000
Internal error: Oops: 7 [#1] SMP ARM
..
CPU: 0 UID: 0 PID: 70 Comm: cat Not tainted 7.0.0-rc2-next-20260302+ #26 VOLUNTARY
..
PC is at __read_once_word_nocheck+0x0/0x8
LR is at unwind_frame+0x6b0/0xa90
...
Call trace:
__read_once_word_nocheck from unwind_frame+0x6b0/0xa90
unwind_frame from unwind_backtrace+0x178/0x1e0
unwind_backtrace from show_stack+0x10/0x14
...

ARM64 also takes care of it in dump_backtrace(), so same logic
is added for ARM also.

Fixes: 18ed1c01a7dd ("ARM: smp: Enable THREAD_INFO_IN_TASK")
Signed-off-by: Maninder Singh <maninder1.s@xxxxxxxxxxx>
---
arch/arm/kernel/traps.c | 9 +++++++--
arch/arm/kernel/unwind.c | 10 ++++++++--
2 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index afbd2ebe5c39..770dcb1dc683 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -221,11 +221,14 @@ void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk,
unsigned int fp, mode;
int ok = 1;

- printk("%sCall trace: ", loglvl);
-
if (!tsk)
tsk = current;

+ if (!try_get_task_stack(tsk))
+ return;
+
+ printk("%sCall trace: ", loglvl);
+
if (regs) {
fp = frame_pointer(regs);
mode = processor_mode(regs);
@@ -249,6 +252,8 @@ void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk,

if (ok)
c_backtrace(fp, mode, loglvl);
+
+ put_task_stack(tsk);
}
#endif

diff --git a/arch/arm/kernel/unwind.c b/arch/arm/kernel/unwind.c
index c91cb0e1585e..990692714288 100644
--- a/arch/arm/kernel/unwind.c
+++ b/arch/arm/kernel/unwind.c
@@ -29,6 +29,7 @@
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/module.h>
+#include <linux/sched/task_stack.h>

#include <asm/stacktrace.h>
#include <asm/traps.h>
@@ -524,13 +525,16 @@ void unwind_backtrace(struct pt_regs *regs, struct task_struct *tsk,
{
struct stackframe frame;

- printk("%sCall trace: ", loglvl);
-
pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);

if (!tsk)
tsk = current;

+ if (!try_get_task_stack(tsk))
+ return;
+
+ printk("%sCall trace: ", loglvl);
+
if (regs) {
arm_get_current_stackframe(regs, &frame);
/* PC might be corrupted, use LR in that case. */
@@ -567,6 +571,8 @@ void unwind_backtrace(struct pt_regs *regs, struct task_struct *tsk,
break;
dump_backtrace_entry(where, frame.pc, frame.sp - 4, loglvl);
}
+
+ put_task_stack(tsk);
}

struct unwind_table *unwind_table_add(unsigned long start, unsigned long size,
--
2.34.1