From 872df694064f45c90cb3903034b78a4c9957ca7c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 20 Oct 2026 08:34:26 -1000 Subject: [PATCH] alpha: use scoped user access when setting up signal frames setup_sigcontext() writes the whole register set with __put_user() and __copy_to_user(), OR-ing the errors together, relying on its callers' access_ok() on the frame. setup_frame() and setup_rt_frame() write the sigreturn trampoline, and setup_rt_frame() the ucontext header, the same way. Do those writes inside scoped_user_write_access() with unsafe_put_user() and unsafe_copy_to_user(). on_sig_stack() is evaluated before the scope, and the instruction cache flush stays outside it. The up-front access_ok() calls stay: setup_rt_frame() still needs its own for the __copy_to_user() of the signal mask. A fault part way through now stops at the first failing write instead of carrying on. Either way the frame setup fails and the task gets SIGSEGV. alpha has no user_access_begin(), so the accesses themselves are the same as before. This is part of getting rid of __get_user() and __put_user() entirely. Signed-off-by: Linus Torvalds --- arch/alpha/kernel/signal.c | 138 ++++++++++++++++++++----------------- 1 file changed, 73 insertions(+), 65 deletions(-) diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index fa6f6c8732c3..9ab266164665 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -284,62 +284,66 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask, unsigned long sp) { struct switch_stack *sw = (struct switch_stack *)regs - 1; - long err = 0; + long onstack = on_sig_stack((unsigned long)sc); - err |= __put_user(on_sig_stack((unsigned long)sc), &sc->sc_onstack); - err |= __put_user(mask, &sc->sc_mask); - err |= __put_user(regs->pc, &sc->sc_pc); - err |= __put_user(8, &sc->sc_ps); + scoped_user_write_access(sc, Efault) { + unsafe_put_user(onstack, &sc->sc_onstack, Efault); + unsafe_put_user(mask, &sc->sc_mask, Efault); + unsafe_put_user(regs->pc, &sc->sc_pc, Efault); + unsafe_put_user(8, &sc->sc_ps, Efault); - err |= __put_user(regs->r0 , sc->sc_regs+0); - err |= __put_user(regs->r1 , sc->sc_regs+1); - err |= __put_user(regs->r2 , sc->sc_regs+2); - err |= __put_user(regs->r3 , sc->sc_regs+3); - err |= __put_user(regs->r4 , sc->sc_regs+4); - err |= __put_user(regs->r5 , sc->sc_regs+5); - err |= __put_user(regs->r6 , sc->sc_regs+6); - err |= __put_user(regs->r7 , sc->sc_regs+7); - err |= __put_user(regs->r8 , sc->sc_regs+8); - err |= __put_user(sw->r9 , sc->sc_regs+9); - err |= __put_user(sw->r10 , sc->sc_regs+10); - err |= __put_user(sw->r11 , sc->sc_regs+11); - err |= __put_user(sw->r12 , sc->sc_regs+12); - err |= __put_user(sw->r13 , sc->sc_regs+13); - err |= __put_user(sw->r14 , sc->sc_regs+14); - err |= __put_user(sw->r15 , sc->sc_regs+15); - err |= __put_user(regs->r16, sc->sc_regs+16); - err |= __put_user(regs->r17, sc->sc_regs+17); - err |= __put_user(regs->r18, sc->sc_regs+18); - err |= __put_user(regs->r19, sc->sc_regs+19); - err |= __put_user(regs->r20, sc->sc_regs+20); - err |= __put_user(regs->r21, sc->sc_regs+21); - err |= __put_user(regs->r22, sc->sc_regs+22); - err |= __put_user(regs->r23, sc->sc_regs+23); - err |= __put_user(regs->r24, sc->sc_regs+24); - err |= __put_user(regs->r25, sc->sc_regs+25); - err |= __put_user(regs->r26, sc->sc_regs+26); - err |= __put_user(regs->r27, sc->sc_regs+27); - err |= __put_user(regs->r28, sc->sc_regs+28); - err |= __put_user(regs->gp , sc->sc_regs+29); - err |= __put_user(sp, sc->sc_regs+30); - err |= __put_user(0, sc->sc_regs+31); + unsafe_put_user(regs->r0, sc->sc_regs+0, Efault); + unsafe_put_user(regs->r1, sc->sc_regs+1, Efault); + unsafe_put_user(regs->r2, sc->sc_regs+2, Efault); + unsafe_put_user(regs->r3, sc->sc_regs+3, Efault); + unsafe_put_user(regs->r4, sc->sc_regs+4, Efault); + unsafe_put_user(regs->r5, sc->sc_regs+5, Efault); + unsafe_put_user(regs->r6, sc->sc_regs+6, Efault); + unsafe_put_user(regs->r7, sc->sc_regs+7, Efault); + unsafe_put_user(regs->r8, sc->sc_regs+8, Efault); + unsafe_put_user(sw->r9, sc->sc_regs+9, Efault); + unsafe_put_user(sw->r10, sc->sc_regs+10, Efault); + unsafe_put_user(sw->r11, sc->sc_regs+11, Efault); + unsafe_put_user(sw->r12, sc->sc_regs+12, Efault); + unsafe_put_user(sw->r13, sc->sc_regs+13, Efault); + unsafe_put_user(sw->r14, sc->sc_regs+14, Efault); + unsafe_put_user(sw->r15, sc->sc_regs+15, Efault); + unsafe_put_user(regs->r16, sc->sc_regs+16, Efault); + unsafe_put_user(regs->r17, sc->sc_regs+17, Efault); + unsafe_put_user(regs->r18, sc->sc_regs+18, Efault); + unsafe_put_user(regs->r19, sc->sc_regs+19, Efault); + unsafe_put_user(regs->r20, sc->sc_regs+20, Efault); + unsafe_put_user(regs->r21, sc->sc_regs+21, Efault); + unsafe_put_user(regs->r22, sc->sc_regs+22, Efault); + unsafe_put_user(regs->r23, sc->sc_regs+23, Efault); + unsafe_put_user(regs->r24, sc->sc_regs+24, Efault); + unsafe_put_user(regs->r25, sc->sc_regs+25, Efault); + unsafe_put_user(regs->r26, sc->sc_regs+26, Efault); + unsafe_put_user(regs->r27, sc->sc_regs+27, Efault); + unsafe_put_user(regs->r28, sc->sc_regs+28, Efault); + unsafe_put_user(regs->gp, sc->sc_regs+29, Efault); + unsafe_put_user(sp, sc->sc_regs+30, Efault); + unsafe_put_user(0, sc->sc_regs+31, Efault); - err |= __copy_to_user(sc->sc_fpregs, - current_thread_info()->fp, 31 * 8); - err |= __put_user(0, sc->sc_fpregs+31); - err |= __put_user(current_thread_info()->fp[31], &sc->sc_fpcr); + unsafe_copy_to_user(sc->sc_fpregs, + current_thread_info()->fp, 31 * 8, Efault); + unsafe_put_user(0, sc->sc_fpregs+31, Efault); + unsafe_put_user(current_thread_info()->fp[31], &sc->sc_fpcr, Efault); - err |= __put_user(regs->trap_a0, &sc->sc_traparg_a0); - err |= __put_user(regs->trap_a1, &sc->sc_traparg_a1); - err |= __put_user(regs->trap_a2, &sc->sc_traparg_a2); + unsafe_put_user(regs->trap_a0, &sc->sc_traparg_a0, Efault); + unsafe_put_user(regs->trap_a1, &sc->sc_traparg_a1, Efault); + unsafe_put_user(regs->trap_a2, &sc->sc_traparg_a2, Efault); + } + return 0; - return err; +Efault: + return -EFAULT; } static int setup_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) { - unsigned long oldsp, r26, err = 0; + unsigned long oldsp, r26; struct sigframe __user *frame; oldsp = rdusp(); @@ -347,25 +351,22 @@ setup_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) if (!access_ok(frame, sizeof(*frame))) return -EFAULT; - err |= setup_sigcontext(&frame->sc, regs, set->sig[0], oldsp); - if (err) + if (setup_sigcontext(&frame->sc, regs, set->sig[0], oldsp)) return -EFAULT; /* Set up to return from userspace. If provided, use a stub already in userspace. */ r26 = (unsigned long) ksig->ka.ka_restorer; if (!r26) { - err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0); - err |= __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1); - err |= __put_user(INSN_CALLSYS, frame->retcode+2); + scoped_user_write_access(frame, Efault) { + unsafe_put_user(INSN_MOV_R30_R16, frame->retcode+0, Efault); + unsafe_put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1, Efault); + unsafe_put_user(INSN_CALLSYS, frame->retcode+2, Efault); + } imb(); r26 = (unsigned long) frame->retcode; } - /* Check that everything was written properly. */ - if (err) - return err; - /* "Return" to the handler */ regs->r26 = r26; regs->r27 = regs->pc = (unsigned long) ksig->ka.sa.sa_handler; @@ -379,6 +380,9 @@ setup_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) current->comm, current->pid, frame, regs->pc, regs->r26); #endif return 0; + +Efault: + return -EFAULT; } static int @@ -395,9 +399,11 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) err |= copy_siginfo_to_user(&frame->info, &ksig->info); /* Create the ucontext. */ - err |= __put_user(0, &frame->uc.uc_flags); - err |= __put_user(0, &frame->uc.uc_link); - err |= __put_user(set->sig[0], &frame->uc.uc_osf_sigmask); + scoped_user_write_access(frame, Efault) { + unsafe_put_user(0, &frame->uc.uc_flags, Efault); + unsafe_put_user(0, &frame->uc.uc_link, Efault); + unsafe_put_user(set->sig[0], &frame->uc.uc_osf_sigmask, Efault); + } err |= __save_altstack(&frame->uc.uc_stack, oldsp); err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0], oldsp); @@ -409,17 +415,16 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) already in userspace. */ r26 = (unsigned long) ksig->ka.ka_restorer; if (!r26) { - err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0); - err |= __put_user(INSN_LDI_R0+__NR_rt_sigreturn, - frame->retcode+1); - err |= __put_user(INSN_CALLSYS, frame->retcode+2); + scoped_user_write_access(frame, Efault) { + unsafe_put_user(INSN_MOV_R30_R16, frame->retcode+0, Efault); + unsafe_put_user(INSN_LDI_R0+__NR_rt_sigreturn, + frame->retcode+1, Efault); + unsafe_put_user(INSN_CALLSYS, frame->retcode+2, Efault); + } imb(); r26 = (unsigned long) frame->retcode; } - if (err) - return -EFAULT; - /* "Return" to the handler */ regs->r26 = r26; regs->r27 = regs->pc = (unsigned long) ksig->ka.sa.sa_handler; @@ -434,6 +439,9 @@ setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) #endif return 0; + +Efault: + return -EFAULT; }