public inbox for linux-arm-kernel@lists.infradead.org
 help / color / mirror / Atom feed
* [PATCH 1/1] arm: get task_stack reference before dump_backtrace
       [not found] <CGME20260305070534epcas5p378bb22ef9f1a895d7736ed2272c19ec6@epcas5p3.samsung.com>
@ 2026-03-05  7:05 ` Maninder Singh
  2026-03-08 23:39   ` Linus Walleij
  2026-03-08 23:52   ` Russell King (Oracle)
  0 siblings, 2 replies; 5+ messages in thread
From: Maninder Singh @ 2026-03-05  7:05 UTC (permalink / raw)
  To: linux, rmk+kernel, bigeasy, peterz, kees, ardb, keithpac, linusw
  Cc: linux-arm-kernel, linux-kernel, Maninder Singh

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@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



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/1] arm: get task_stack reference before dump_backtrace
  2026-03-05  7:05 ` [PATCH 1/1] arm: get task_stack reference before dump_backtrace Maninder Singh
@ 2026-03-08 23:39   ` Linus Walleij
  2026-03-08 23:52   ` Russell King (Oracle)
  1 sibling, 0 replies; 5+ messages in thread
From: Linus Walleij @ 2026-03-08 23:39 UTC (permalink / raw)
  To: Maninder Singh
  Cc: linux, rmk+kernel, bigeasy, peterz, kees, ardb, keithpac,
	linux-arm-kernel, linux-kernel

On Thu, Mar 5, 2026 at 8:05 AM Maninder Singh <maninder1.s@samsung.com> wrote:

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

Ard B should review this but it looks right to me:
Acked-by: Linus Walleij <linusw@kernel.org>

Yours,
Linus Walleij


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/1] arm: get task_stack reference before dump_backtrace
  2026-03-05  7:05 ` [PATCH 1/1] arm: get task_stack reference before dump_backtrace Maninder Singh
  2026-03-08 23:39   ` Linus Walleij
@ 2026-03-08 23:52   ` Russell King (Oracle)
  2026-03-09  5:53     ` Maninder Singh
  1 sibling, 1 reply; 5+ messages in thread
From: Russell King (Oracle) @ 2026-03-08 23:52 UTC (permalink / raw)
  To: Maninder Singh
  Cc: bigeasy, peterz, kees, ardb, keithpac, linusw, linux-arm-kernel,
	linux-kernel

On Thu, Mar 05, 2026 at 12:35:27PM +0530, Maninder Singh wrote:
> 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)

Looking at x86, it also has THREAD_INFO_IN_TASK, but I see nothing like
this in show_stack(). How come x86 isn't similarly buggy?

> 
> 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
> ...

"otherwise if someone calls show_stack() for task" ... and the stack
trace given stops at show_stack() and doesn't show the "someone".

I'd like to know _how_ this happens, and why ARM64 and now 32-bit ARM
are different from x86.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!


^ permalink raw reply	[flat|nested] 5+ messages in thread

* RE: [PATCH 1/1] arm: get task_stack reference before dump_backtrace
  2026-03-08 23:52   ` Russell King (Oracle)
@ 2026-03-09  5:53     ` Maninder Singh
  2026-03-09  5:55       ` Maninder Singh
  0 siblings, 1 reply; 5+ messages in thread
From: Maninder Singh @ 2026-03-09  5:53 UTC (permalink / raw)
  To: Russell King (Oracle)
  Cc: bigeasy@linutronix.de, peterz@infradead.org, kees@kernel.org,
	ardb@kernel.org, keithpac@amazon.com, linusw@kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org

Hi,

>> 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)
>
> Looking at x86, it also has THREAD_INFO_IN_TASK, but I see nothing like
> this in show_stack(). How come x86 isn't similarly buggy?

I think x86 also has same issue, some of other architectures which supports
THREAD_INFO_IN_TASK has added try_get_task_stack() in show_stack(), but not *all*

   8   2293  arch/powerpc/kernel/process.c <<show_stack>>
             if (!try_get_task_stack(tsk))

   4    488  arch/arm64/kernel/stacktrace.c <<dump_backtrace>>
             if (!try_get_task_stack(tsk))


>> 
>> ...
>
>"otherwise if someone calls show_stack() for task" ... and the stack
>trace given stops at show_stack() and doesn't show the "someone".
>
>I'd like to know _how_ this happens, and why ARM64 and now 32-bit ARM
>are different from x86.

I tried to simulate same thing on x86_64, it is also crashing.

Just a dummy code to save task_struct to reproduce the race:

+       rcu_read_lock();
+       for_each_process(p) {
+               if (!strcmp(p->comm, "sleep")) {
+                       check_task = p;
+                       get_task_struct(p);
+                       pr_emerg("get done for %s %d\n", p->comm, p->pid);
+               }
+       }
+       rcu_read_unlock();

// in mean time here sleep binary will be exited.

+       show_stack(check_task,  NULL, KERN_EMERG);

//OOPs

/ # cat /proc/meminfo
[   49.885891] Call Trace:
[   49.887151] BUG: unable to handle page fault for address: ffffb57400213de8
[   49.887563] #PF: supervisor read access in kernel mode
[   49.887737] #PF: error_code(0x0000) - not-present page
[   49.887999] PGD 1000067 P4D 1000067 PUD 113b067 PMD 1bcb067 PTE 0
[   49.888588] Oops: Oops: 0000 [#1] SMP NOPTI
[   49.889329] CPU: 0 UID: 0 PID: 68 Comm: cat Not tainted 7.0.0-rc2-next-20260302-00003-gb7e059f3a5ae-dirty #49 PREEMPT(lazy)
[   49.889789] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
[   49.890204] RIP: 0010:__unwind_start+0x118/0x1c0
[   49.890471] Code: 75 28 48 8d b8 ff 0f 00 00 48 81 e7 00 f0 ff ff e8 ed ce fb ff 85 c0 75 ae eb 9c 48 8b 86 08 0c 00 00 48 8d 78 38 48 89 7d 48 <48> 8b 50 28 48 89 55 50 48 8b 4c
[   49.891163] RSP: 0018:ffffb57400207b00 EFLAGS: 00000246
[   49.891385] RAX: ffffb57400213dc0 RBX: ffffb57400213dc0 RCX: 0000000000000000
[   49.891615] RDX: 0000000000000000 RSI: ffff99ec41b6cc40 RDI: ffffb57400213df8
[   49.891867] RBP: ffffb57400207b68 R08: ffffffffae53e908 R09: 00000000ffffdfff
[   49.892101] R10: ffffffffae45e920 R11: ffffffffae50e920 R12: 0000000000000000
[   49.892332] R13: ffff99ec41b6f298 R14: ffffb57400207b68 R15: ffffffffae24615e
[   49.892670] FS:  00000000081ed3c0(0000) GS:ffff99ec9887b000(0000) knlGS:0000000000000000
[   49.892950] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   49.893147] CR2: ffffb57400213de8 CR3: 0000000001d2d000 CR4: 00000000000006f0
[   49.893485] Call Trace:
[   49.893700]  <TASK>
[   49.893810]  __show_trace_log_lvl+0x31f/0x360
[   49.893988]  ? mas_store_prealloc+0x99/0x2c0
[   49.894169]  meminfo_proc_show+0xdd/0x9a0
[   49.894312]  ? seq_open+0x3b/0x60
[   49.894435]  ? __pfx_meminfo_proc_show+0x10/0x10
[   49.894568]  ? file_ra_state_init+0x10/0x30
[   49.894731]  ? __pte_offset_map+0x16/0xd0
[   49.894871]  ? seq_read_iter+0x38e/0x4b0
[   49.895004]  seq_read_iter+0x109/0x4b0
[   49.895125]  copy_splice_read+0x18f/0x330
[   49.895272]  splice_direct_to_actor+0xb4/0x250
[   49.895420]  ? __pfx_direct_splice_actor+0x10/0x10
[   49.895582]  do_splice_direct+0x71/0xb0
[   49.895730]  ? __pfx_direct_file_splice_eof+0x10/0x10
[   49.895908]  do_sendfile+0x361/0x420
[   49.896049]  do_syscall_64+0xf1/0x520
[   49.896197]  entry_SYSCALL_64_after_hwframe+0x77/0x7f
[   49.896375] RIP: 0033:0x4a8d3e
[   49.896634] Code: c3 0f 1f 00 4c 89 d2 4c 89 c6 e9 fd fd ff ff 0f 1f 44 00 00 31 c0 c3 0f 1f 44 00 00 f3 0f 1e fa 49 89 ca b8 28 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c8
[   49.897221] RSP: 002b:00007ffe75342478 EFLAGS: 00000246 ORIG_RAX: 0000000000000028
[   49.897486] RAX: ffffffffffffffda RBX: 0000000001000000 RCX: 00000000004a8d3e
[   49.897747] RDX: 0000000000000000 RSI: 0000000000000003 RDI: 0000000000000001
[   49.897977] RBP: 0000000000000003 R08: 0000000000000001 R09: 0000000000000000
[   49.898221] R10: 0000000001000000 R11: 0000000000000246 R12: 0000000000000003
[   49.898489] R13: 0000000000000001 R14: 0000000000000000 R15: 0000000000000001
[   49.898764]  </TASK>
[   49.898898] Modules linked in:
[   49.899259] CR2: ffffb57400213de8
[   49.899762] ---[ end trace 0000000000000000 ]---
[   49.900187] RIP: 0010:__unwind_start+0x118/0x1c0
[   49.900391] Code: 75 28 48 8d b8 ff 0f 00 00 48 81 e7 00 f0 ff ff e8 ed ce fb ff 85 c0 75 ae eb 9c 48 8b 86 08 0c 00 00 48 8d 78 38 48 89 7d 48 <48> 8b 50 28 48 89 55 50 48 8b 4c
[   49.901001] RSP: 0018:ffffb57400207b00 EFLAGS: 00000246
[   49.901188] RAX: ffffb57400213dc0 RBX: ffffb57400213dc0 RCX: 0000000000000000
[   49.901431] RDX: 0000000000000000 RSI: ffff99ec41b6cc40 RDI: ffffb57400213df8
[   49.901680] RBP: ffffb57400207b68 R08: ffffffffae53e908 R09: 00000000ffffdfff
[   49.901918] R10: ffffffffae45e920 R11: ffffffffae50e920 R12: 0000000000000000
[   49.902182] R13: ffff99ec41b6f298 R14: ffffb57400207b68 R15: ffffffffae24615e
[   49.902417] FS:  00000000081ed3c0(0000) GS:ffff99ec9887b000(0000) knlGS:0000000000000000
[   49.902694] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   49.902896] CR2: ffffb57400213de8 CR3: 0000000001d2d000 CR4: 00000000000006f0


So It has to be same way for all archs, as mentioned in Help of THREAD_INFO_IN_TASK

config THREAD_INFO_IN_TASK
        bool
        help
          Select this to move thread_info off the stack into task_struct.  To
          make this work, an arch will need to remove all thread_info fields
          except flags and fix any runtime bugs.

          One subtle change that will be needed is to use try_get_task_stack()
          and put_task_stack() in save_thread_stack_tsk() and save_thread_stack_tsk().

alongwith save_thread_stack_tsk and save_thread_stack_tsk, same thing shall be done for show_stack also.

Thanks & Regards,
Maninder Singh


^ permalink raw reply	[flat|nested] 5+ messages in thread

* RE: [PATCH 1/1] arm: get task_stack reference before dump_backtrace
  2026-03-09  5:53     ` Maninder Singh
@ 2026-03-09  5:55       ` Maninder Singh
  0 siblings, 0 replies; 5+ messages in thread
From: Maninder Singh @ 2026-03-09  5:55 UTC (permalink / raw)
  To: Russell King (Oracle)
  Cc: bigeasy@linutronix.de, peterz@infradead.org, kees@kernel.org,
	ardb@kernel.org, keithpac@amazon.com, linusw@kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org

> So It has to be same way for all archs, as mentioned in Help of THREAD_INFO_IN_TASK
> 
> config THREAD_INFO_IN_TASK
>         bool
>         help
>           Select this to move thread_info off the stack into task_struct.  To
>           make this work, an arch will need to remove all thread_info fields
>           except flags and fix any runtime bugs.
> 
>           One subtle change that will be needed is to use try_get_task_stack()
>           and put_task_stack() in save_thread_stack_tsk() and save_thread_stack_tsk().
> 
> alongwith save_thread_stack_tsk and save_thread_stack_tsk, same thing shall be done for show_stack also.

Typo error:

config THREAD_INFO_IN_TASK
        bool
        help
          Select this to move thread_info off the stack into task_struct.  To
          make this work, an arch will need to remove all thread_info fields
          except flags and fix any runtime bugs.

          One subtle change that will be needed is to use try_get_task_stack()
          and put_task_stack() in save_thread_stack_tsk() and get_wchan().

alongwith save_thread_stack_tsk() and get_wchan(), same thing shall be done for show_stack() also.


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-03-09  5:56 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <CGME20260305070534epcas5p378bb22ef9f1a895d7736ed2272c19ec6@epcas5p3.samsung.com>
2026-03-05  7:05 ` [PATCH 1/1] arm: get task_stack reference before dump_backtrace Maninder Singh
2026-03-08 23:39   ` Linus Walleij
2026-03-08 23:52   ` Russell King (Oracle)
2026-03-09  5:53     ` Maninder Singh
2026-03-09  5:55       ` Maninder Singh

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox