]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
riscv: Fix register corruption from uninitialized cregs on error
authorMichael Neuling <mikey@neuling.org>
Fri, 1 May 2026 06:23:20 +0000 (06:23 +0000)
committerPaul Walmsley <pjw@kernel.org>
Sat, 2 May 2026 03:11:31 +0000 (21:11 -0600)
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
Link: https://patch.msgid.link/20260501062320.2339562-1-mikey@neuling.org
Signed-off-by: Paul Walmsley <pjw@kernel.org>
arch/riscv/kernel/compat_signal.c
arch/riscv/kernel/ptrace.c

index 6ec4e34255a9abdcdb18fb126f83bbf7a80b9aeb..cf3eb33a11e464c6c453ad02dd8ebbc67d8dc136 100644 (file)
@@ -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);
 
index 93de2e7a30747d93d2ebc51f5d2c59c16cdd9718..793bcee4618282957e77293858d2835435523e2e 100644 (file)
@@ -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;
 }