RE: [PATCH 1/1] arm: get task_stack reference before dump_backtrace
From: Maninder Singh
Date: Mon Mar 09 2026 - 01:53:43 EST
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