mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
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 <torvalds@linux-foundation.org>
This commit is contained in:
parent
9622c1bc29
commit
872df69406
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user