]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
riscv: stacktrace: Disable KASAN checks for non-current tasks
authorChunyan Zhang <zhangchunyan@iscas.ac.cn>
Mon, 27 Oct 2025 17:40:43 +0000 (11:40 -0600)
committerPaul Walmsley <pjw@kernel.org>
Mon, 27 Oct 2025 17:40:43 +0000 (11:40 -0600)
Unwinding the stack of a task other than current, KASAN would report
"BUG: KASAN: out-of-bounds in walk_stackframe+0x41c/0x460"

There is a same issue on x86 and has been resolved by the commit
84936118bdf3 ("x86/unwind: Disable KASAN checks for non-current tasks")
The solution could be applied to RISC-V too.

This patch also can solve the issue:
https://seclists.org/oss-sec/2025/q4/23

Fixes: 5d8544e2d007 ("RISC-V: Generic library routines and assembly")
Co-developed-by: Jiakai Xu <xujiakai2025@iscas.ac.cn>
Signed-off-by: Jiakai Xu <xujiakai2025@iscas.ac.cn>
Signed-off-by: Chunyan Zhang <zhangchunyan@iscas.ac.cn>
Link: https://lore.kernel.org/r/20251022072608.743484-1-zhangchunyan@iscas.ac.cn
[pjw@kernel.org: clean up checkpatch issues]
Signed-off-by: Paul Walmsley <pjw@kernel.org>
arch/riscv/kernel/stacktrace.c

index 3fe9e6edef8f1ce8ea8ca34ce49254f352527faf..b41b6255751cb1dc53277c19f438e5729ec3e303 100644 (file)
 
 #ifdef CONFIG_FRAME_POINTER
 
+/*
+ * 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;                                            \
+})
+
 extern asmlinkage void handle_exception(void);
 extern unsigned long ret_from_exception_end;
 
@@ -69,8 +85,9 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
                        fp = frame->ra;
                        pc = regs->ra;
                } else {
-                       fp = frame->fp;
-                       pc = ftrace_graph_ret_addr(current, &graph_idx, frame->ra,
+                       fp = READ_ONCE_TASK_STACK(task, frame->fp);
+                       pc = READ_ONCE_TASK_STACK(task, frame->ra);
+                       pc = ftrace_graph_ret_addr(current, &graph_idx, pc,
                                                   &frame->ra);
                        if (pc >= (unsigned long)handle_exception &&
                            pc < (unsigned long)&ret_from_exception_end) {