KASAN: out-of-bounds Read in proc_pid_stack (3)

Status: moderation: reported on 2026/08/27 09:06
Subsystems: fs
Labels: prio:normal
[Documentation on labels]
Reported-by: syzbot+8f7fb5704be2c5784ac5@syzkaller.appspotmail.com
First crash: 80d, last: 80d
✨ AI-generated root cause summary:

In arch/riscv/kernel/stacktrace.c, READ_ONCE_TASK_STACK(task, x) was introduced to disable KASAN checks when unwinding another task's stack (which may contain KASAN-poisoned redzones or be concurrently modified). However, the macro implementation assigns 'unsigned long addr = x;' prior to branching on whether task is current. Because x is an lvalue (frame->fp or frame->ra), this assignment performs a normal KASAN-instrumented 8-byte load from the remote stack into the local variable addr, and then passes the local variable addr to READ_ONCE_NOCHECK(addr), completely defeating the intended KASAN bypass and triggering an out-of-bounds report.

▶ ▼ ✨ Full AI root cause analysis
Based on kernel commit 77ae27fd98f3:

Technical Breakdown and Root Cause Analysis

1. Relevant Code and Architecture Context

When unwinding a kernel stack on RISC-V with frame pointers enabled (CONFIG_FRAME_POINTER), arch_stack_walk() invokes walk_stackframe() (arch/riscv/kernel/stacktrace.c).

When inspecting or dumping the stack of another task (e.g. via /proc/$PID/stack using proc_pid_stack() in fs/proc/base.c or via __get_wchan()), the target task may be running concurrently on another CPU. As functions execute and return on that target task, stack frames are allocated and reclaimed, and KASAN redzones around local stack variables are poisoned and unpoisoned. If the unwinder reads a poisoned stack slot on that task's stack, KASAN will flag the read as an out-of-bounds access.

To address this, READ_ONCE_TASK_STACK(task, x) was introduced in arch/riscv/kernel/stacktrace.c to mimic the x86 unwinder macro, intended to use READ_ONCE_NOCHECK() (which loads memory via uninstrumented __read_once_word_nocheck()) when task != current.

2. Root Cause Defect in READ_ONCE_TASK_STACK

In arch/riscv/kernel/stacktrace.c:

/*
 * This disables KASAN checking when reading a value from another task's stack,
 * since the other task could be running on another CPU and could have poisoned
 * the stack in the meantime.
 */
#define READ_ONCE_TASK_STACK(task, x)			\
({							\
	unsigned long val;				\
	unsigned long addr = x;				\
	if ((task) == current)				\
		val = READ_ONCE(addr);			\
	else						\
		val = READ_ONCE_NOCHECK(addr);		\
	val;						\
})

At the call sites in walk_stackframe():

	fp = READ_ONCE_TASK_STACK(task, frame->fp);
	pc = READ_ONCE_TASK_STACK(task, frame->ra);

The callers pass an lvalue (frame->fp or frame->ra). In READ_ONCE_TASK_STACK, the macro initializes the local temporary:

	unsigned long addr = x;
  1. Because x is frame->fp, the assignment addr = x; generates a direct 8-byte load from &(frame->fp). Because walk_stackframe() is compiled with KASAN instrumentation, this direct load is checked against KASAN shadow memory. If that stack slot is marked poisoned (e.g., matching redzone markers 0xf1 or 0xf3), KASAN immediately triggers a false-positive out-of-bounds report at walk_stackframe+0x512/0x56a arch/riscv/kernel/stacktrace.c:88.
  2. Furthermore, passing addr to READ_ONCE_NOCHECK(addr) expands to:
    (typeof(addr))__read_once_word_nocheck(&(addr));
    
    This takes the address of addr on the local current task's stack and reads addr without KASAN checking. The remote stack memory at &(frame->fp) was already loaded without protection during the initial assignment to addr.

3. Correct Pattern

In contrast to the buggy RISC-V implementation, the x86 implementation (arch/x86/include/asm/unwind.h) avoids any preliminary assignment:

#define READ_ONCE_TASK_STACK(task, x)			\
({							\
	unsigned long val;				\
	if (task == current)				\
		val = READ_ONCE(x);			\
	else						\
		val = READ_ONCE_NOCHECK(x);		\
	val;						\
})

By passing x directly to READ_ONCE_NOCHECK(x), &(x) yields &(frame->fp), and the dereference is performed safely by __read_once_word_nocheck() with __no_sanitize_or_inline, preventing KASAN checks on remote task stacks as intended.

▶ ▼ ✨ AI Jobs (8)
ID Workflow Result Correct Bug Created Started Finished Revision
e2d2f25b assessment-security DenialOfService: ❌ Exploitable: ❌ FilesystemTrigger: ❌ FuzzingArtifact: ❌ MemoryCorruption: ❌ NetworkNeedsSetup: ❌ NetworkTrigger: ❌ PeripheralTrigger: ❌ RemoteTrigger: ❌ Unprivileged: ❌ UserNamespace: ❌ VMGuestTrigger: ❌ VMHostTrigger: ❌ ❓ KASAN: out-of-bounds Read in proc_pid_stack (3) 2026/11/06 00:36 2026/11/06 00:36 2026/11/06 01:05 5cecaf1f
84358102 assessment-security 💥 KASAN: out-of-bounds Read in proc_pid_stack (3) 2026/09/28 01:06 2026/09/28 01:06 2026/09/28 01:06 a3c7249d
f816963a assessment-security 💥 KASAN: out-of-bounds Read in proc_pid_stack (3) 2026/09/12 00:00 2026/09/12 00:01 2026/09/12 00:01 6816f32e
4563d35c assessment-security 💥 KASAN: out-of-bounds Read in proc_pid_stack (3) 2026/09/03 00:49 2026/09/03 00:49 2026/09/03 00:49 9941e97d
92ff4c2e assessment-security 💥 KASAN: out-of-bounds Read in proc_pid_stack (3) 2026/08/30 00:01 2026/08/30 00:01 2026/08/30 00:01 2f52988a
1a8ac379 repro-c 💥 KASAN: out-of-bounds Read in proc_pid_stack (3) 2026/08/27 10:03 2026/08/27 10:03 2026/08/27 10:46 69a01293
390ec123 assessment-security 💥 KASAN: out-of-bounds Read in proc_pid_stack (3) 2026/08/27 01:32 2026/08/27 01:32 2026/08/27 01:32 a2b77b9e
e41020a6 assessment-security 💥 KASAN: out-of-bounds Read in proc_pid_stack (3) 2026/08/25 00:23 2026/08/25 00:23 2026/08/25 00:23 23caa175
▶ ▼ Similar bugs (4)
Kernel Title Rank 🛈 Repro Cause bisect Fix bisect Count Last Reported Patched Status
upstream KASAN: out-of-bounds Read in proc_pid_stack fuse 17 syz 3 674d 674d 0/29 closed as dup on 2025/01/06 10:20
upstream KASAN: out-of-bounds Read in proc_pid_stack (2) fs 17 3 411d 495d 0/29 auto-obsoleted due to no activity on 2025/12/24 23:05
upstream KASAN: stack-out-of-bounds Read in proc_pid_stack (2) fs 17 1 851d 810d 0/29 auto-obsoleted due to no activity on 2024/10/21 18:27
upstream KASAN: stack-out-of-bounds Read in proc_pid_stack riscv 17 3 1254d 1289d 22/29 fixed on 2023/06/08 14:41

Sample crash report:
==================================================================
BUG: KASAN: out-of-bounds in walk_stackframe+0x512/0x56a arch/riscv/kernel/stacktrace.c:88
Read of size 8 at addr ffff8f800a077890 by task syz.0.5/3893

CPU: 1 UID: 0 PID: 3893 Comm: syz.0.5 Not tainted syzkaller #0 PREEMPT 
Hardware name: riscv-virtio,qemu (DT)
Call Trace:
[<ffffffff8007e614>] dump_backtrace+0x2e/0x3c arch/riscv/kernel/stacktrace.c:149
[<ffffffff80003112>] show_stack+0x30/0x3c arch/riscv/kernel/stacktrace.c:155
[<ffffffff800630cc>] __dump_stack lib/dump_stack.c:94 [inline]
[<ffffffff800630cc>] dump_stack_lvl+0x114/0x1aa lib/dump_stack.c:120
[<ffffffff8000e264>] print_address_description mm/kasan/report.c:378 [inline]
[<ffffffff8000e264>] print_report+0x27a/0x592 mm/kasan/report.c:482
[<ffffffff80bf8576>] kasan_report+0xf0/0x26c mm/kasan/report.c:595
[<ffffffff80bfa226>] __asan_report_load8_noabort+0x12/0x1a mm/kasan/report_generic.c:381
[<ffffffff8007e0d0>] walk_stackframe+0x512/0x56a arch/riscv/kernel/stacktrace.c:88
[<ffffffff86594bd4>] arch_stack_walk+0x1c/0x24 arch/riscv/kernel/stacktrace.c:182
[<ffffffff803f99b2>] stack_trace_save_tsk+0x164/0x1f2 kernel/stacktrace.c:150
[<ffffffff80f94ea6>] proc_pid_stack+0x16c/0x278 fs/proc/base.c:490
[<ffffffff80f970bc>] proc_single_show+0xea/0x1ca fs/proc/base.c:793
[<ffffffff80dd2ef4>] traverse.part.0.constprop.0+0x126/0x542 fs/seq_file.c:112
[<ffffffff80dd3b08>] traverse fs/seq_file.c:99 [inline]
[<ffffffff80dd3b08>] seq_read_iter+0x7f8/0x1090 fs/seq_file.c:196
[<ffffffff80dd4654>] seq_read+0x2b4/0x434 fs/seq_file.c:163
[<ffffffff80d0743e>] vfs_read+0x2a2/0xbc6 fs/read_write.c:572
[<ffffffff80d0a63a>] ksys_pread64 fs/read_write.c:764 [inline]
[<ffffffff80d0a63a>] __do_sys_pread64 fs/read_write.c:772 [inline]
[<ffffffff80d0a63a>] __se_sys_pread64 fs/read_write.c:769 [inline]
[<ffffffff80d0a63a>] __riscv_sys_pread64+0x1d6/0x230 fs/read_write.c:769
[<ffffffff8007af94>] syscall_handler+0x92/0x114 arch/riscv/include/asm/syscall.h:112
[<ffffffff86594576>] do_trap_ecall_u+0x4ca/0x658 arch/riscv/kernel/traps.c:341
[<ffffffff865c0d08>] handle_exception+0x168/0x174 arch/riscv/kernel/entry.S:237

The buggy address belongs to a 8-page vmalloc region starting at 0xffff8f800a070000 allocated at kernel_clone+0x198/0xf7c kernel/fork.c:2772
The buggy address belongs to the physical page:
page: refcount:1 mapcount:0 mapping:0000000000000000 index:0x0 pfn:0xb1497
memcg:ffffaf802022f902
flags: 0x0(node=0|zone=0)
raw: 0000000000000000 0000000000000000 ffff8d8002c525c8 0000000000000000
raw: 0000000000000000 0000000000000000 00000001ffffffff ffffaf802022f902
page dumped because: kasan: bad access detected
page_owner tracks the page as allocated
page last allocated via order 0, migratetype Unmovable, gfp_mask 0x29c2(GFP_NOWAIT|__GFP_HIGHMEM|__GFP_IO|__GFP_FS|__GFP_ZERO), pid 3443, tgid 3443 (kworker/u8:5), ts 1028450241900, free_ts 993049465600
 __set_page_owner+0x92/0x4b0 mm/page_owner.c:341
 set_page_owner include/linux/page_owner.h:32 [inline]
 post_alloc_hook+0xe4/0x1a0 mm/page_alloc.c:1859
 prep_new_page mm/page_alloc.c:1867 [inline]
 get_page_from_freelist+0x914/0x3950 mm/page_alloc.c:3946
 __alloc_frozen_pages_noprof+0x224/0x2e58 mm/page_alloc.c:5304
 alloc_pages_mpol+0x1f0/0x59c mm/mempolicy.c:2490
 alloc_frozen_pages_noprof+0x156/0x2ce mm/mempolicy.c:2561
 alloc_pages_noprof+0x20/0x140 mm/mempolicy.c:2581
 vm_area_alloc_pages mm/vmalloc.c:3689 [inline]
 __vmalloc_area_node mm/vmalloc.c:3914 [inline]
 __vmalloc_node_range_noprof+0x103e/0x1b34 mm/vmalloc.c:4104
 __vmalloc_node_noprof+0xfc/0x132 mm/vmalloc.c:4165
 alloc_thread_stack_node kernel/fork.c:359 [inline]
 dup_task_struct kernel/fork.c:930 [inline]
 copy_process+0x762/0x81b6 kernel/fork.c:2139
 kernel_clone+0x198/0xf7c kernel/fork.c:2772
 user_mode_thread+0xd8/0x114 kernel/fork.c:2849
 call_usermodehelper_exec_sync kernel/umh.c:130 [inline]
 call_usermodehelper_exec_work+0x6e/0x196 kernel/umh.c:161
 process_one_work+0x9c6/0x22b2 kernel/workqueue.c:3387
 process_scheduled_works kernel/workqueue.c:3470 [inline]
 worker_thread+0x532/0xcaa kernel/workqueue.c:3551
 kthread+0x312/0x438 kernel/kthread.c:436
page last free pid 3254 tgid 3254 stack trace:
 __reset_page_owner+0x76/0x1bc mm/page_owner.c:320
 reset_page_owner include/linux/page_owner.h:25 [inline]
 __free_pages_prepare mm/page_alloc.c:1406 [inline]
 __free_frozen_pages+0x6b2/0x136e mm/page_alloc.c:2950
 free_frozen_pages+0xe/0x16 mm/page_alloc.c:2988
 __free_slab+0xda/0x250 mm/slub.c:3441
 free_slab+0x28/0x16c mm/slub.c:3475
 discard_slab mm/slub.c:3481 [inline]
 __slab_free+0x23c/0x2f8 mm/slub.c:5741
 ___cache_free+0x94/0xac mm/slub.c:6449
 qlink_free mm/kasan/quarantine.c:163 [inline]
 qlist_free_all+0x64/0x134 mm/kasan/quarantine.c:179
 kasan_quarantine_reduce+0x152/0x1b4 mm/kasan/quarantine.c:286
 __kasan_slab_alloc+0x5c/0x82 mm/kasan/common.c:350
 kasan_slab_alloc include/linux/kasan.h:253 [inline]
 slab_post_alloc_hook mm/slub.c:4584 [inline]
 slab_alloc_node mm/slub.c:4917 [inline]
 __do_kmalloc_node mm/slub.c:5333 [inline]
 __kmalloc_noprof+0x25e/0x8cc mm/slub.c:5359
 _kmalloc_noprof include/linux/slab.h:992 [inline]
 _kzalloc_noprof include/linux/slab.h:1309 [inline]
 fib6_info_alloc+0x46/0x142 net/ipv6/ip6_fib.c:155
 ip6_route_info_create+0x128/0x8d4 net/ipv6/route.c:3833
 ip6_route_add+0x4a/0x1ca net/ipv6/route.c:3962
 addrconf_prefix_route+0x2b0/0x4d0 net/ipv6/addrconf.c:2504
 inet6_addr_add+0x456/0x89e net/ipv6/addrconf.c:3077

Memory state around the buggy address:
 ffff8f800a077780: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 ffff8f800a077800: 00 00 00 00 f1 f1 f1 f1 00 00 f3 f3 00 00 00 00
>ffff8f800a077880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
                            ^
 ffff8f800a077900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 ffff8f800a077980: f1 f1 f1 f1 f1 f1 00 00 00 00 00 00 00 00 00 00
==================================================================

Crashes (1):
Time Kernel Commit Syzkaller Config Log Report Syz repro C repro VM info Assets (help?) Manager Title
2026/08/23 09:01 git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux.git for-next 77ae27fd98f3 1e72964b .config console log report info [disk image (non-bootable)] [vmlinux] [kernel image] ci-qemu2-riscv64 KASAN: out-of-bounds Read in proc_pid_stack
* Struck through repros no longer work on HEAD.