[PATCH v2] riscv: Fix register corruption from uninitialized cregs on error

Michael Neuling posted 1 patch 1 month, 1 week ago
arch/riscv/kernel/compat_signal.c | 2 ++
arch/riscv/kernel/ptrace.c        | 4 ++--
2 files changed, 4 insertions(+), 2 deletions(-)
[PATCH v2] riscv: Fix register corruption from uninitialized cregs on error
Posted by Michael Neuling 1 month, 1 week ago
compat_riscv_gpr_set() calls cregs_to_regs() unconditionally, even when
user_regset_copyin() fails. Since cregs is an uninitialized stack
variable, a copyin failure causes uninitialized stack data to be written
into the target task's pt_regs, corrupting its register state and
potentially leaking kernel stack contents.

compat_restore_sigcontext() has the same issue: it calls cregs_to_regs()
even when __copy_from_user() fails, leading to the same corruption of
the signal-returning task's register state on error.

Only call cregs_to_regs() when the user copy succeeds.

Fixes: 4608c159594f ("riscv: compat: ptrace: Add compat_arch_ptrace implement")
Fixes: 7383ee05314b ("riscv: compat: signal: Add rt_frame implementation")
Signed-off-by: Michael Neuling <mikey@neuling.org>
Assisted-by: Cursor:claude-4.6-opus-high-thinking
---
 arch/riscv/kernel/compat_signal.c | 2 ++
 arch/riscv/kernel/ptrace.c        | 4 ++--
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/arch/riscv/kernel/compat_signal.c b/arch/riscv/kernel/compat_signal.c
index 6ec4e34255..cf3eb33a11 100644
--- a/arch/riscv/kernel/compat_signal.c
+++ b/arch/riscv/kernel/compat_signal.c
@@ -107,6 +107,8 @@ static long compat_restore_sigcontext(struct pt_regs *regs,
 
 	/* sc_regs is structured the same as the start of pt_regs */
 	err = __copy_from_user(&cregs, &sc->sc_regs, sizeof(sc->sc_regs));
+	if (unlikely(err))
+		return err;
 
 	cregs_to_regs(&cregs, regs);
 
diff --git a/arch/riscv/kernel/ptrace.c b/arch/riscv/kernel/ptrace.c
index 93de2e7a30..793bcee461 100644
--- a/arch/riscv/kernel/ptrace.c
+++ b/arch/riscv/kernel/ptrace.c
@@ -577,8 +577,8 @@ static int compat_riscv_gpr_set(struct task_struct *target,
 	struct compat_user_regs_struct cregs;
 
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &cregs, 0, -1);
-
-	cregs_to_regs(&cregs, task_pt_regs(target));
+	if (!ret)
+		cregs_to_regs(&cregs, task_pt_regs(target));
 
 	return ret;
 }
-- 
2.43.0
Re: [PATCH v2] riscv: Fix register corruption from uninitialized cregs on error
Posted by Paul Walmsley 1 month, 1 week ago
On Fri, 1 May 2026, Michael Neuling wrote:

> compat_riscv_gpr_set() calls cregs_to_regs() unconditionally, even when
> user_regset_copyin() fails. Since cregs is an uninitialized stack
> variable, a copyin failure causes uninitialized stack data to be written
> into the target task's pt_regs, corrupting its register state and
> potentially leaking kernel stack contents.
> 
> compat_restore_sigcontext() has the same issue: it calls cregs_to_regs()
> even when __copy_from_user() fails, leading to the same corruption of
> the signal-returning task's register state on error.
> 
> Only call cregs_to_regs() when the user copy succeeds.
> 
> Fixes: 4608c159594f ("riscv: compat: ptrace: Add compat_arch_ptrace implement")
> Fixes: 7383ee05314b ("riscv: compat: signal: Add rt_frame implementation")
> Signed-off-by: Michael Neuling <mikey@neuling.org>
> Assisted-by: Cursor:claude-4.6-opus-high-thinking

Thanks very much; queued for v7.1-rc.


- Paul