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

Maninder Singh maninder1.s at samsung.com
Wed Mar 4 23:05:27 PST 2026


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 at samsung.com>
---
 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




More information about the linux-arm-kernel mailing list