[PATCH] sh: prevent ptrace from changing privileged SR bits

Jérémy Jean <[email protected]>
Newsgroups org.kernel.vger.linux-sh,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
PTRACE_POKEUSR writes every word in struct pt_regs, including SR, without
filtering privileged bits. The general register regset setter exposes the
same write through PTRACE_SETREGS and PTRACE_SETREGSET.

The exception return path restores the saved SR with rte after adjusting
only the interrupt mask. An unprivileged same-UID tracer can set SR.MD and
make its tracee resume at a user address in privileged mode.

Preserve the saved non-user SR bits in both write paths and accept only
the bits in SR_USER_MASK. Recompose SR after user_regset_copyin() even on
error because the copy may have updated a prefix of the register set.

Assisted-by: Codex:gpt-5
Signed-off-by: Jérémy Jean <[email protected]>
---
 arch/sh/kernel/ptrace_32.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c
index 8794081483fb..bb69c35cb9a7 100644
--- a/arch/sh/kernel/ptrace_32.c
+++ b/arch/sh/kernel/ptrace_32.c
@@ -146,6 +146,7 @@ static int genregs_set(struct task_struct *target,
 		       const void *kbuf, const void __user *ubuf)
 {
 	struct pt_regs *regs = task_pt_regs(target);
+	unsigned long sr = regs->sr & ~SR_USER_MASK;
 	int ret;
 
 	ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
@@ -159,6 +160,7 @@ static int genregs_set(struct task_struct *target,
 	if (!ret)
 		user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
 					  sizeof(struct pt_regs), -1);
+	regs->sr = (regs->sr & SR_USER_MASK) | sr;
 
 	return ret;
 }
@@ -391,6 +393,11 @@ long arch_ptrace(struct task_struct *child, long request,
 		    addr > sizeof(struct user) - 3)
 			break;
 
+		if (addr == offsetof(struct pt_regs, sr)) {
+			unsigned long sr = get_stack_long(child, addr);
+
+			data = (data & SR_USER_MASK) | (sr & ~SR_USER_MASK);
+		}
 		if (addr < sizeof(struct pt_regs))
 			ret = put_stack_long(child, addr, data);
 		else if (addr >= offsetof(struct user, fpu) &&
-- 
2.47.3
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.