diff options
| author | Michael Neuling <mikey@neuling.org> | 2026-05-01 06:23:20 +0000 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2026-09-02 14:29:17 +0200 |
| commit | 66dedb6028c3df6c6a3372dd935b823917e150d5 (patch) | |
| tree | 24508be6f145265ab34b8d924ee9f630807e5fb9 | |
| parent | 5662dac41a3442aa378d7c405164903eb109fc05 (diff) | |
| download | linux-stable-66dedb6028c3df6c6a3372dd935b823917e150d5.tar.gz linux-stable-66dedb6028c3df6c6a3372dd935b823917e150d5.zip | |
riscv: Fix register corruption from uninitialized cregs on error
[ Upstream commit 6ebcbb53fc9bc30843054ed99fd60b8e542628f4 ]
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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
| -rw-r--r-- | arch/riscv/kernel/compat_signal.c | 2 | ||||
| -rw-r--r-- | 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 6ec4e34255a9..cf3eb33a11e4 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 2afe460de16a..be412db2ba1f 100644 --- a/arch/riscv/kernel/ptrace.c +++ b/arch/riscv/kernel/ptrace.c @@ -327,8 +327,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; } |
