diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2016-05-10 18:39:54 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2016-05-10 18:39:54 +0000 |
commit | 869ce5a1007a9d00bbac5121d825c80be70f9dde (patch) | |
tree | 26cd16954837176d7032fd1841853c34c5b32f99 /sys/arch | |
parent | 24ed245ec22671d3d288d52c91f39a81a24637bf (diff) |
SROP mitigation. sendsig() stores a (per-process ^ &sigcontext) cookie
inside the sigcontext. sigreturn(2) checks syscall entry was from the
exact PC addr in the (per-process ASLR) sigtramp, verifies the cookie,
and clears it to prevent sigcontext reuse.
not yet tested on landisk, sparc, *88k, socppc.
ok kettenis
Diffstat (limited to 'sys/arch')
36 files changed, 396 insertions, 144 deletions
diff --git a/sys/arch/alpha/alpha/locore.s b/sys/arch/alpha/alpha/locore.s index 86d893c30fb..6d6354f079f 100644 --- a/sys/arch/alpha/alpha/locore.s +++ b/sys/arch/alpha/alpha/locore.s @@ -1,4 +1,4 @@ -/* $OpenBSD: locore.s,v 1.43 2015/07/20 07:45:23 dlg Exp $ */ +/* $OpenBSD: locore.s,v 1.44 2016/05/10 18:39:40 deraadt Exp $ */ /* $NetBSD: locore.s,v 1.94 2001/04/26 03:10:44 ross Exp $ */ /*- @@ -273,6 +273,8 @@ NESTED(sigcode,0,0,ra,0,0) ldq a0, 0(sp) /* get the sigcontext pointer */ lda sp, 16(sp) CALLSYS_NOERROR(sigreturn) /* and call sigreturn() with it. */ + .globl sigcoderet +sigcoderet: mov v0, a0 /* if that failed, get error code */ CALLSYS_NOERROR(exit) /* and call exit() with it. */ XNESTED(esigcode,0) diff --git a/sys/arch/alpha/alpha/machdep.c b/sys/arch/alpha/alpha/machdep.c index 8f38df9011f..944ae9705e7 100644 --- a/sys/arch/alpha/alpha/machdep.c +++ b/sys/arch/alpha/alpha/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.171 2015/10/21 07:59:17 mpi Exp $ */ +/* $OpenBSD: machdep.c,v 1.172 2016/05/10 18:39:40 deraadt Exp $ */ /* $NetBSD: machdep.c,v 1.210 2000/06/01 17:12:38 thorpej Exp $ */ /*- @@ -1477,9 +1477,7 @@ sendsig(catcher, sig, mask, code, type, val) } else sip = NULL; - /* - * copy the frame out to userland. - */ + ksc.sc_cookie = (long)scp ^ p->p_p->ps_sigcookie; if (copyout((caddr_t)&ksc, (caddr_t)scp, kscsize) != 0) { trash: #ifdef DEBUG @@ -1542,9 +1540,7 @@ sys_sigreturn(p, v, retval) } */ *uap = v; struct sigcontext ksc; struct fpreg *fpregs = (struct fpreg *)&ksc.sc_fpregs; -#ifdef DEBUG - struct sigcontext *scp; -#endif + struct sigcontext *scp = SCARG(uap, sigcntxp); int error; #ifdef DEBUG @@ -1552,13 +1548,28 @@ sys_sigreturn(p, v, retval) printf("sigreturn: pid %d, scp %p\n", p->p_pid, scp); #endif + if (PROC_PC(p) != p->p_p->ps_sigcoderet) { + printf("%s(%d): sigreturn not from tramp [pc 0x%lx 0x%lx]\n", + p->p_comm, p->p_pid, PROC_PC(p), p->p_p->ps_sigcoderet); + sigexit(p, SIGILL); + return (EPERM); + } + /* * Test and fetch the context structure. * We grab it all at once for speed. */ - if ((error = copyin(SCARG(uap, sigcntxp), &ksc, sizeof(ksc))) != 0) + if ((error = copyin(scp, &ksc, sizeof(ksc))) != 0) return (error); + if (ksc.sc_cookie != ((long)scp ^ p->p_p->ps_sigcookie)) { + printf("%s(%d): cookie %lx should have been %lx\n", + p->p_comm, p->p_pid, ksc.sc_cookie, + (long)scp ^ p->p_p->ps_sigcookie); + sigexit(p, SIGILL); + return (EFAULT); + } + if (ksc.sc_regs[R_ZERO] != 0xACEDBADE) /* magic number */ return (EINVAL); /* diff --git a/sys/arch/alpha/include/signal.h b/sys/arch/alpha/include/signal.h index b79b2770689..b080e2553f8 100644 --- a/sys/arch/alpha/include/signal.h +++ b/sys/arch/alpha/include/signal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: signal.h,v 1.9 2015/11/07 19:06:05 miod Exp $ */ +/* $OpenBSD: signal.h,v 1.10 2016/05/10 18:39:42 deraadt Exp $ */ /* $NetBSD: signal.h,v 1.2 1995/02/16 03:08:08 cgd Exp $ */ /* @@ -47,8 +47,8 @@ typedef int sig_atomic_t; * representations of 'struct reg' and 'struct fpreg', respectively. */ struct sigcontext { - long __sc_unused; - long sc_mask; /* signal mask to restore */ + long sc_cookie; + long sc_mask; /* signal mask to restore XXX should be int */ long sc_pc; /* pc to restore */ long sc_ps; /* ps to restore */ unsigned long sc_regs[32]; /* integer register set (see above) */ diff --git a/sys/arch/amd64/amd64/locore.S b/sys/arch/amd64/amd64/locore.S index f66dc562df8..bad043377b4 100644 --- a/sys/arch/amd64/amd64/locore.S +++ b/sys/arch/amd64/amd64/locore.S @@ -1,4 +1,4 @@ -/* $OpenBSD: locore.S,v 1.77 2016/05/10 14:15:57 mikeb Exp $ */ +/* $OpenBSD: locore.S,v 1.78 2016/05/10 18:39:42 deraadt Exp $ */ /* $NetBSD: locore.S,v 1.13 2004/03/25 18:33:17 drochner Exp $ */ /* @@ -763,6 +763,8 @@ NENTRY(sigcode) pushq %rdi /* fake return address */ movq $SYS_sigreturn,%rax syscall + .globl _C_LABEL(sigcoderet) +_C_LABEL(sigcoderet): movq $SYS_exit,%rax syscall .globl _C_LABEL(esigcode) diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c index 8d2db71e90d..d0a145ab3ee 100644 --- a/sys/arch/amd64/amd64/machdep.c +++ b/sys/arch/amd64/amd64/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.218 2016/04/03 17:48:33 guenther Exp $ */ +/* $OpenBSD: machdep.c,v 1.219 2016/05/10 18:39:42 deraadt Exp $ */ /* $NetBSD: machdep.c,v 1.3 2003/05/07 22:58:18 fvdl Exp $ */ /*- @@ -571,6 +571,7 @@ sendsig(sig_t catcher, int sig, int mask, u_long code, int type, } scp = sp - sss; + ksc.sc_cookie = (long)scp ^ p->p_p->ps_sigcookie; if (copyout(&ksc, (void *)scp, sizeof(ksc))) sigexit(p, SIGILL); @@ -611,18 +612,34 @@ sys_sigreturn(struct proc *p, void *v, register_t *retval) struct sys_sigreturn_args /* { syscallarg(struct sigcontext *) sigcntxp; } */ *uap = v; - struct sigcontext *scp, ksc; + struct sigcontext *scp = SCARG(uap, sigcntxp), ksc; struct trapframe *tf = p->p_md.md_regs; int error; - scp = SCARG(uap, sigcntxp); -#ifdef DEBUG - if ((sigdebug & SDB_FOLLOW) && (!sigpid || p->p_pid == sigpid)) - printf("sigreturn: pid %d, scp %p\n", p->p_pid, scp); -#endif + if (PROC_PC(p) != p->p_p->ps_sigcoderet) { + printf("%s(%d): sigreturn not from tramp [pc 0x%llx %lx]\n", + p->p_comm, p->p_pid, PROC_PC(p), p->p_p->ps_sigcoderet); + sigexit(p, SIGILL); + return (EPERM); + } + if ((error = copyin((caddr_t)scp, &ksc, sizeof ksc))) return (error); + if (ksc.sc_cookie != ((long)scp ^ p->p_p->ps_sigcookie)) { + printf("%s(%d): cookie %lx should have been %lx\n", + p->p_comm, p->p_pid, ksc.sc_cookie, + (long)scp ^ p->p_p->ps_sigcookie); + sigexit(p, SIGILL); + return (EFAULT); + } + + /* Prevent reuse of the sigcontext cookie */ + ksc.sc_cookie = 0; + (void)copyout(&ksc.sc_cookie, (caddr_t)scp + + offsetof(struct sigcontext, sc_cookie), + sizeof (ksc.sc_cookie)); + if (((ksc.sc_rflags ^ tf->tf_rflags) & PSL_USERSTATIC) != 0 || !USERMODE(ksc.sc_cs, ksc.sc_eflags)) return (EINVAL); diff --git a/sys/arch/amd64/include/signal.h b/sys/arch/amd64/include/signal.h index 527a220cf32..e5cffc53b1d 100644 --- a/sys/arch/amd64/include/signal.h +++ b/sys/arch/amd64/include/signal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: signal.h,v 1.8 2013/04/01 17:18:19 deraadt Exp $ */ +/* $OpenBSD: signal.h,v 1.9 2016/05/10 18:39:42 deraadt Exp $ */ /* $NetBSD: signal.h,v 1.2 2003/04/28 23:16:17 bjh21 Exp $ */ /* @@ -83,6 +83,7 @@ struct sigcontext { struct fxsave64 *sc_fpstate; int __sc_unused; int sc_mask; + long sc_cookie; }; #endif /* __BSD_VISIBLE || __XPG_VISIBLE >= 420 */ #endif /* !_MACHINE_SIGNAL_H_ */ diff --git a/sys/arch/arm/arm/sig_machdep.c b/sys/arch/arm/arm/sig_machdep.c index abd1bd494a3..6f308d4cab7 100644 --- a/sys/arch/arm/arm/sig_machdep.c +++ b/sys/arch/arm/arm/sig_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sig_machdep.c,v 1.12 2016/01/31 00:14:50 jsg Exp $ */ +/* $OpenBSD: sig_machdep.c,v 1.13 2016/05/10 18:39:43 deraadt Exp $ */ /* $NetBSD: sig_machdep.c,v 1.22 2003/10/08 00:28:41 thorpej Exp $ */ /* @@ -136,6 +136,7 @@ sendsig(sig_t catcher, int sig, int returnmask, u_long code, int type, initsiginfo(&frame.sf_si, sig, code, type, val); } + frame.sf_sc.sc_cookie = (long)&fp->sf_sc ^ p->p_p->ps_sigcookie; if (copyout(&frame, fp, sizeof(frame)) != 0) { /* * Process has trashed its stack; give it an illegal @@ -182,23 +183,32 @@ sys_sigreturn(struct proc *p, void *v, register_t *retval) struct sys_sigreturn_args /* { syscallarg(struct sigcontext *) sigcntxp; } */ *uap = v; - struct sigcontext *scp, context; + struct sigcontext *scp = SCARG(uap, sigcntxp), context; struct trapframe *tf; - /* - * we do a rather scary test in userland - */ - if (v == NULL) + if (PROC_PC(p) != p->p_p->ps_sigcoderet) { + printf("%s(%d): sigreturn not from tramp [pc 0x%lx %lx]\n", + p->p_comm, p->p_pid, PROC_PC(p), p->p_p->ps_sigcoderet); + sigexit(p, SIGILL); + return (EPERM); + } + + if (copyin(scp, &context, sizeof(*scp)) != 0) return (EFAULT); - - /* - * The trampoline code hands us the context. - * It is unsafe to keep track of it ourselves, in the event that a - * program jumps out of a signal handler. - */ - scp = SCARG(uap, sigcntxp); - if (copyin((caddr_t)scp, &context, sizeof(*scp)) != 0) + + if (context.sc_cookie != ((long)scp ^ p->p_p->ps_sigcookie)) { + printf("%s(%d): cookie %lx should have been %lx\n", + p->p_comm, p->p_pid, context.sc_cookie, + (long)scp ^ p->p_p->ps_sigcookie); + sigexit(p, SIGILL); return (EFAULT); + } + + /* Prevent reuse of the sigcontext cookie */ + context.sc_cookie = 0; + (void)copyout(&context.sc_cookie, (caddr_t)scp + + offsetof(struct sigcontext, sc_cookie), + sizeof (context.sc_cookie)); /* * Make sure the processor mode has not been tampered with and diff --git a/sys/arch/arm/arm/sigcode.S b/sys/arch/arm/arm/sigcode.S index c6c8412fc97..dc38068e482 100644 --- a/sys/arch/arm/arm/sigcode.S +++ b/sys/arch/arm/arm/sigcode.S @@ -1,4 +1,4 @@ -/* $OpenBSD: sigcode.S,v 1.2 2006/12/27 17:49:26 drahn Exp $ */ +/* $OpenBSD: sigcode.S,v 1.3 2016/05/10 18:39:43 deraadt Exp $ */ /* $NetBSD: sigcode.S,v 1.6 2003/10/05 19:44:58 matt Exp $ */ /* @@ -52,6 +52,8 @@ ENTRY_NP(sigcode) add r0, sp, #SIGF_SC ldr r12, =SYS_sigreturn swi SYS_sigreturn + .globl _C_LABEL(sigcoderet) +_C_LABEL(sigcoderet): /* Well if that failed we better exit quick ! */ diff --git a/sys/arch/arm/include/signal.h b/sys/arch/arm/include/signal.h index 564ea4f5bfc..773fdc89dc0 100644 --- a/sys/arch/arm/include/signal.h +++ b/sys/arch/arm/include/signal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: signal.h,v 1.8 2012/12/02 07:03:31 guenther Exp $ */ +/* $OpenBSD: signal.h,v 1.9 2016/05/10 18:39:43 deraadt Exp $ */ /* $NetBSD: signal.h,v 1.5 2003/10/18 17:57:21 briggs Exp $ */ /* @@ -61,8 +61,8 @@ typedef int sig_atomic_t; * a non-standard exit is performed. */ struct sigcontext { - int __sc_unused; - int sc_mask; /* signal mask to restore (old style) */ + long sc_cookie; + int sc_mask; /* signal mask to restore */ unsigned int sc_spsr; unsigned int sc_r0; diff --git a/sys/arch/hppa/hppa/locore.S b/sys/arch/hppa/hppa/locore.S index 3a47c461961..037e3b8e72a 100644 --- a/sys/arch/hppa/hppa/locore.S +++ b/sys/arch/hppa/hppa/locore.S @@ -1,4 +1,4 @@ -/* $OpenBSD: locore.S,v 1.193 2014/10/23 16:57:45 miod Exp $ */ +/* $OpenBSD: locore.S,v 1.194 2016/05/10 18:39:44 deraadt Exp $ */ /* * Copyright (c) 1998-2004 Michael Shalayeff @@ -3042,6 +3042,8 @@ sigcode_call .call ble 4(sr7, r1) ldi SYS_sigreturn, t1 + .globl sigcoderet +sigcoderet: ldil L%SYSCALLGATE, r1 copy ret0, arg0 diff --git a/sys/arch/hppa/hppa/machdep.c b/sys/arch/hppa/hppa/machdep.c index a98fc8c4030..98578044850 100644 --- a/sys/arch/hppa/hppa/machdep.c +++ b/sys/arch/hppa/hppa/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.243 2016/04/20 23:52:04 dlg Exp $ */ +/* $OpenBSD: machdep.c,v 1.244 2016/05/10 18:39:44 deraadt Exp $ */ /* * Copyright (c) 1999-2003 Michael Shalayeff @@ -1303,6 +1303,7 @@ sendsig(sig_t catcher, int sig, int mask, u_long code, int type, p->p_pid, sig, scp, ksc.sc_fp, tf->tf_sp); #endif + ksc.sc_cookie = (long)scp ^ p->p_p->ps_sigcookie; if (copyout(&ksc, (void *)scp, sizeof(ksc))) sigexit(p, SIGILL); @@ -1325,11 +1326,17 @@ sys_sigreturn(struct proc *p, void *v, register_t *retval) struct sys_sigreturn_args /* { syscallarg(struct sigcontext *) sigcntxp; } */ *uap = v; - struct sigcontext *scp, ksc; + struct sigcontext *scp = SCARG(uap, sigcntxp), ksc; struct trapframe *tf = p->p_md.md_regs; int error; - scp = SCARG(uap, sigcntxp); + if (PROC_PC(p) != p->p_p->ps_sigcoderet) { + printf("%s(%d): sigreturn not from tramp [pc 0x%lx 0x%lx]\n", + p->p_comm, p->p_pid, PROC_PC(p), p->p_p->ps_sigcoderet); + sigexit(p, SIGILL); + return (EPERM); + } + #ifdef DEBUG if ((sigdebug & SDB_FOLLOW) && (!sigpid || p->p_pid == sigpid)) printf("sigreturn: pid %d, scp %p\n", p->p_pid, scp); @@ -1341,6 +1348,20 @@ sys_sigreturn(struct proc *p, void *v, register_t *retval) if ((error = copyin((caddr_t)scp, (caddr_t)&ksc, sizeof ksc))) return (error); + if (ksc.sc_cookie != ((long)scp ^ p->p_p->ps_sigcookie)) { + printf("%s(%d): cookie %lx should have been %lx\n", + p->p_comm, p->p_pid, ksc.sc_cookie, + (long)scp ^ p->p_p->ps_sigcookie); + sigexit(p, SIGILL); + return (EFAULT); + } + + /* Prevent reuse of the sigcontext cookie */ + ksc.sc_cookie = 0; + (void)copyout(&ksc.sc_cookie, (caddr_t)scp + + offsetof(struct sigcontext, sc_cookie), + sizeof (ksc.sc_cookie)); + #define PSL_MBS (PSL_C|PSL_Q|PSL_P|PSL_D|PSL_I) #define PSL_MBZ (PSL_Y|PSL_Z|PSL_S|PSL_X|PSL_M|PSL_R) if ((ksc.sc_ps & (PSL_MBS|PSL_MBZ)) != PSL_MBS) diff --git a/sys/arch/hppa/include/signal.h b/sys/arch/hppa/include/signal.h index 629a9410d58..850e56accb3 100644 --- a/sys/arch/hppa/include/signal.h +++ b/sys/arch/hppa/include/signal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: signal.h,v 1.11 2013/04/01 17:18:20 deraadt Exp $ */ +/* $OpenBSD: signal.h,v 1.12 2016/05/10 18:39:44 deraadt Exp $ */ /* * Copyright (c) 1994, The University of Utah and @@ -48,7 +48,7 @@ typedef int sig_atomic_t; */ struct sigcontext { unsigned long __sc_unused; - unsigned long sc_mask; /* signal mask to restore */ + long sc_mask; /* signal mask to restore XXX should be int */ unsigned long sc_ps; /* psl to restore */ unsigned long sc_fp; /* fp to restore */ unsigned long sc_pcoqh; /* pc offset queue (head) to restore */ @@ -56,6 +56,7 @@ struct sigcontext { unsigned long sc_resv[2]; unsigned long sc_regs[32]; unsigned long sc_fpregs[64]; + long sc_cookie; }; #endif /* __BSD_VISIBLE || __XPG_VISIBLE >= 420 */ #endif /* !_MACHINE_SIGNAL_H_ */ diff --git a/sys/arch/hppa64/hppa64/locore.S b/sys/arch/hppa64/hppa64/locore.S index d6b28a6957f..4e4eb338529 100644 --- a/sys/arch/hppa64/hppa64/locore.S +++ b/sys/arch/hppa64/hppa64/locore.S @@ -1,4 +1,4 @@ -/* $OpenBSD: locore.S,v 1.41 2011/10/12 18:30:09 miod Exp $ */ +/* $OpenBSD: locore.S,v 1.42 2016/05/10 18:39:44 deraadt Exp $ */ /* * Copyright (c) 2005 Michael Shalayeff @@ -1970,6 +1970,8 @@ ENTRY(sigcode,0) .call ble 4(%sr7, %r1) ldi SYS_sigreturn, %r1 + .globl sigcoderet +sigcoderet: ldil L%SYSCALLGATE, %r1 depd %r0, 31, 32, %r1 diff --git a/sys/arch/hppa64/hppa64/machdep.c b/sys/arch/hppa64/hppa64/machdep.c index 005a9a20eae..fe2cdbaa294 100644 --- a/sys/arch/hppa64/hppa64/machdep.c +++ b/sys/arch/hppa64/hppa64/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.79 2016/04/20 23:52:04 dlg Exp $ */ +/* $OpenBSD: machdep.c,v 1.80 2016/05/10 18:39:44 deraadt Exp $ */ /* * Copyright (c) 2005 Michael Shalayeff @@ -900,6 +900,7 @@ sendsig(sig_t catcher, int sig, int mask, u_long code, int type, p->p_pid, sig, scp, ksc.sc_fp, tf->tf_sp); #endif + ksc.sc_cookie = (long)scp ^ p->p_p->ps_sigcookie; if (copyout(&ksc, (void *)scp, sizeof(ksc))) sigexit(p, SIGILL); @@ -922,15 +923,16 @@ sys_sigreturn(struct proc *p, void *v, register_t *retval) struct sys_sigreturn_args /* { syscallarg(struct sigcontext *) sigcntxp; } */ *uap = v; - struct sigcontext *scp, ksc; + struct sigcontext *scp = SCARG(uap, sigcntxp), ksc; struct trapframe *tf = p->p_md.md_regs; int error; - scp = SCARG(uap, sigcntxp); -#ifdef DEBUG - if ((sigdebug & SDB_FOLLOW) && (!sigpid || p->p_pid == sigpid)) - printf("sigreturn: pid %d, scp %p\n", p->p_pid, scp); -#endif + if (PROC_PC(p) != p->p_p->ps_sigcoderet) { + printf("%s(%d): sigreturn not from tramp [pc 0x%lx 0x%lx]\n", + p->p_comm, p->p_pid, PROC_PC(p), p->p_p->ps_sigcoderet); + sigexit(p, SIGILL); + return (EPERM); + } /* flush the FPU ctx first */ fpu_proc_flush(p); @@ -938,6 +940,20 @@ sys_sigreturn(struct proc *p, void *v, register_t *retval) if ((error = copyin((caddr_t)scp, (caddr_t)&ksc, sizeof ksc))) return (error); + if (ksc.sc_cookie != ((long)scp ^ p->p_p->ps_sigcookie)) { + printf("%s(%d): cookie %lx should have been %lx\n", + p->p_comm, p->p_pid, ksc.sc_cookie, + (long)scp ^ p->p_p->ps_sigcookie); + sigexit(p, SIGILL); + return (EFAULT); + } + + /* Prevent reuse of the sigcontext cookie */ + ksc.sc_cookie = 0; + (void)copyout(&ksc.sc_cookie, (caddr_t)scp + + offsetof(struct sigcontext, sc_cookie), + sizeof (ksc.sc_cookie)); + #define PSL_MBS (PSL_C|PSL_Q|PSL_P|PSL_D|PSL_I) #define PSL_MBZ (PSL_Y|PSL_Z|PSL_S|PSL_X|PSL_M|PSL_R) if ((ksc.sc_ps & (PSL_MBS|PSL_MBZ)) != PSL_MBS) diff --git a/sys/arch/hppa64/include/signal.h b/sys/arch/hppa64/include/signal.h index 31498706cef..536b464df5d 100644 --- a/sys/arch/hppa64/include/signal.h +++ b/sys/arch/hppa64/include/signal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: signal.h,v 1.6 2013/04/01 17:18:20 deraadt Exp $ */ +/* $OpenBSD: signal.h,v 1.7 2016/05/10 18:39:44 deraadt Exp $ */ /* * Copyright (c) 1994, The University of Utah and @@ -47,8 +47,8 @@ typedef int sig_atomic_t; * a non-standard exit is performed. */ struct sigcontext { - unsigned long __sc_unused; - unsigned long sc_mask; /* signal mask to restore */ + long __sc_unused; + long sc_mask; /* signal mask to restore XXX should be int */ unsigned long sc_ps; /* psl to restore */ unsigned long sc_fp; /* fp to restore */ unsigned long sc_pcoqh; /* pc offset queue (head) to restore */ @@ -56,6 +56,7 @@ struct sigcontext { unsigned long sc_resv[2]; unsigned long sc_regs[32]; unsigned long sc_fpregs[64]; + long sc_cookie; }; #endif /* __BSD_VISIBLE || __XPG_VISIBLE >= 420 */ #endif /* !_MACHINE_SIGNAL_H_ */ diff --git a/sys/arch/i386/i386/locore.s b/sys/arch/i386/i386/locore.s index 9581f32d310..f143d75008d 100644 --- a/sys/arch/i386/i386/locore.s +++ b/sys/arch/i386/i386/locore.s @@ -1,4 +1,4 @@ -/* $OpenBSD: locore.s,v 1.167 2016/03/15 03:17:51 guenther Exp $ */ +/* $OpenBSD: locore.s,v 1.168 2016/05/10 18:39:45 deraadt Exp $ */ /* $NetBSD: locore.s,v 1.145 1996/05/03 19:41:19 christos Exp $ */ /*- @@ -697,6 +697,8 @@ NENTRY(sigcode) pushl %eax # junk to fake return address movl $SYS_sigreturn,%eax int $0x80 # enter kernel with args on stack + .globl _C_LABEL(sigcoderet) +_C_LABEL(sigcoderet): movl $SYS_exit,%eax int $0x80 # exit if sigreturn fails .globl _C_LABEL(esigcode) diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c index c7a8caa6b42..405af381a89 100644 --- a/sys/arch/i386/i386/machdep.c +++ b/sys/arch/i386/i386/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.583 2016/03/24 04:56:08 guenther Exp $ */ +/* $OpenBSD: machdep.c,v 1.584 2016/05/10 18:39:45 deraadt Exp $ */ /* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */ /*- @@ -2440,6 +2440,7 @@ sendsig(sig_t catcher, int sig, int mask, u_long code, int type, } /* XXX don't copyout siginfo if not needed? */ + frame.sf_sc.sc_cookie = (long)&fp->sf_sc ^ p->p_p->ps_sigcookie; if (copyout(&frame, fp, sizeof(frame)) != 0) { /* * Process has trashed its stack; give it an illegal @@ -2479,18 +2480,33 @@ sys_sigreturn(struct proc *p, void *v, register_t *retval) struct sys_sigreturn_args /* { syscallarg(struct sigcontext *) sigcntxp; } */ *uap = v; - struct sigcontext *scp, context; + struct sigcontext *scp = SCARG(uap, sigcntxp), context; struct trapframe *tf = p->p_md.md_regs; int error; - /* - * The trampoline code hands us the context. - * It is unsafe to keep track of it ourselves, in the event that a - * program jumps out of a signal handler. - */ - scp = SCARG(uap, sigcntxp); - if (copyin((caddr_t)scp, &context, sizeof(*scp)) != 0) + if (PROC_PC(p) != p->p_p->ps_sigcoderet) { + printf("%s(%d): sigreturn not from tramp [pc 0x%x 0x%lx]\n", + p->p_comm, p->p_pid, PROC_PC(p), p->p_p->ps_sigcoderet); + sigexit(p, SIGILL); + return (EPERM); + } + + if ((error = copyin((caddr_t)scp, &context, sizeof(*scp)))) + return (error); + + if (context.sc_cookie != ((long)scp ^ p->p_p->ps_sigcookie)) { + printf("%s(%d): cookie %lx should have been %lx\n", + p->p_comm, p->p_pid, context.sc_cookie, + (long)scp ^ p->p_p->ps_sigcookie); + sigexit(p, SIGILL); return (EFAULT); + } + + /* Prevent reuse of the sigcontext cookie */ + context.sc_cookie = 0; + (void)copyout(&context.sc_cookie, (caddr_t)scp + + offsetof(struct sigcontext, sc_cookie), + sizeof (context.sc_cookie)); /* * Restore signal context. diff --git a/sys/arch/i386/include/signal.h b/sys/arch/i386/include/signal.h index 790339eb264..e0ead34d9c9 100644 --- a/sys/arch/i386/include/signal.h +++ b/sys/arch/i386/include/signal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: signal.h,v 1.10 2013/04/01 17:18:20 deraadt Exp $ */ +/* $OpenBSD: signal.h,v 1.11 2016/05/10 18:39:45 deraadt Exp $ */ /* $NetBSD: signal.h,v 1.6 1996/01/08 13:51:43 mycroft Exp $ */ /* @@ -70,7 +70,7 @@ struct sigcontext { int sc_esp; int sc_ss; - int __sc_unused; + long sc_cookie; int sc_mask; /* signal mask to restore */ int sc_trapno; /* XXX should be above */ diff --git a/sys/arch/m88k/m88k/sig_machdep.c b/sys/arch/m88k/m88k/sig_machdep.c index d1bab73ab1f..b1fef7fc38f 100644 --- a/sys/arch/m88k/m88k/sig_machdep.c +++ b/sys/arch/m88k/m88k/sig_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sig_machdep.c,v 1.23 2015/02/09 08:48:23 miod Exp $ */ +/* $OpenBSD: sig_machdep.c,v 1.24 2016/05/10 18:39:46 deraadt Exp $ */ /* * Copyright (c) 2014 Miodrag Vallat. * @@ -207,18 +207,35 @@ sys_sigreturn(struct proc *p, void *v, register_t *retval) struct sys_sigreturn_args /* { syscallarg(struct sigcontext *) sigcntxp; } */ *uap = v; - struct sigcontext *scp; + struct sigcontext *scp = SCARG(uap, sigcntxp); struct trapframe *tf; struct sigcontext ksc; - scp = (struct sigcontext *)SCARG(uap, sigcntxp); -#ifdef DEBUG - if (sigdebug & SDB_FOLLOW) - printf("sigreturn: pid %d, scp %p\n", p->p_pid, scp); -#endif - if (((vaddr_t)scp & 3) != 0 || - copyin((caddr_t)scp, (caddr_t)&ksc, sizeof(struct sigcontext))) + if (PROC_PC(p) != p->p_p->ps_sigcoderet) { + printf("%s(%d): sigreturn not from tramp [pc 0x%llx %llx]\n", + p->p_comm, p->p_pid, PROC_PC(p), p->p_p->ps_sigcoderet); + sigexit(p, SIGILL); + return (EPERM); + } + + if (((vaddr_t)scp & 3) != 0) return (EINVAL); + if ((error = copyin((caddr_t)scp, (caddr_t)&ksc, sizeof(*scp)))) + return (error); + + if (ksc.sc_cookie != ((long)scp ^ p->p_p->ps_sigcookie)) { + printf("%s(%d): cookie %lx should have been %lx\n", + p->p_comm, p->p_pid, ksc.sc_cookie, + (long)scp ^ p->p_p->ps_sigcookie); + sigexit(p, SIGILL); + return (EFAULT); + } + + /* Prevent reuse of the sigcontext cookie */ + ksc.sc_cookie = 0; + (void)copyout(&ksc.sc_cookie, (caddr_t)scp + + offsetof(struct sigcontext, sc_cookie), + sizeof (ksc.sc_cookie)); tf = p->p_md.md_tf; scp = &ksc; diff --git a/sys/arch/m88k/m88k/subr.S b/sys/arch/m88k/m88k/subr.S index 6d10b422fea..6504080d79b 100644 --- a/sys/arch/m88k/m88k/subr.S +++ b/sys/arch/m88k/m88k/subr.S @@ -1,4 +1,4 @@ -/* $OpenBSD: subr.S,v 1.24 2014/06/08 13:20:39 miod Exp $ */ +/* $OpenBSD: subr.S,v 1.25 2016/05/10 18:39:46 deraadt Exp $ */ /* * Mach Operating System * Copyright (c) 1993-1992 Carnegie Mellon University @@ -1087,6 +1087,8 @@ ENTRY(sigcode) /* r31 points to sigframe */ ld %r2, %r31, 0 /* pick sigcontext* */ or %r13, %r0, SYS_sigreturn tb0 0, %r0, 450 /* syscall trap, calling sigreturn */ + .globl _C_LABEL(sigcoderet) +_C_LABEL(sigcoderet): NOP | failure return #ifdef dontbother /* sigreturn will not return unless it fails */ NOP | success return diff --git a/sys/arch/macppc/macppc/locore.S b/sys/arch/macppc/macppc/locore.S index 1ed64bd7b0f..f042f47acc6 100644 --- a/sys/arch/macppc/macppc/locore.S +++ b/sys/arch/macppc/macppc/locore.S @@ -1,4 +1,4 @@ -/* $OpenBSD: locore.S,v 1.53 2016/04/25 07:58:14 mpi Exp $ */ +/* $OpenBSD: locore.S,v 1.54 2016/05/10 18:39:46 deraadt Exp $ */ /* $NetBSD: locore.S,v 1.2 1996/10/16 19:33:09 ws Exp $ */ /* @@ -1250,6 +1250,8 @@ _C_LABEL(sigcode): addi %r3,%r1,((16+FPSIG_SIZEOF+15)&~0xf)+SF_SC /* compute &sf_sc */ li %r0,SYS_sigreturn sc /* sigreturn(scp) */ + .globl _C_LABEL(sigcoderet) +_C_LABEL(sigcoderet): li %r0,SYS_exit sc /* exit(errno) */ _C_LABEL(esigcode): diff --git a/sys/arch/macppc/macppc/machdep.c b/sys/arch/macppc/macppc/machdep.c index 58b61ceb31b..7ed9fa69054 100644 --- a/sys/arch/macppc/macppc/machdep.c +++ b/sys/arch/macppc/macppc/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.173 2016/04/20 23:52:04 dlg Exp $ */ +/* $OpenBSD: machdep.c,v 1.174 2016/05/10 18:39:46 deraadt Exp $ */ /* $NetBSD: machdep.c,v 1.4 1996/10/16 19:33:11 ws Exp $ */ /* @@ -481,6 +481,7 @@ sendsig(sig_t catcher, int sig, int mask, u_long code, int type, frame.sf_sip = &fp->sf_si; initsiginfo(&frame.sf_si, sig, code, type, val); } + frame.sf_sc.sc_cookie = (long)fp ^ p->p_p->ps_sigcookie; if (copyout(&frame, fp, sizeof frame) != 0) sigexit(p, SIGILL); @@ -508,12 +509,34 @@ sys_sigreturn(struct proc *p, void *v, register_t *retval) struct sys_sigreturn_args /* { syscallarg(struct sigcontext *) sigcntxp; } */ *uap = v; - struct sigcontext sc; + struct sigcontext sc, *scp = SCARG(uap, sigcntxp); struct trapframe *tf; int error; - if ((error = copyin(SCARG(uap, sigcntxp), &sc, sizeof sc))) + if (PROC_PC(p) != p->p_p->ps_sigcoderet) { + printf("%s(%d): sigreturn not from tramp [pc 0x%x 0x%lx]\n", + p->p_comm, p->p_pid, PROC_PC(p), p->p_p->ps_sigcoderet); + sigexit(p, SIGILL); + return (EPERM); + } + + if ((error = copyin(scp, &sc, sizeof sc))) return error; + + if (sc.sc_cookie != ((long)scp ^ p->p_p->ps_sigcookie)) { + printf("%s(%d): cookie %lx should have been %lx\n", + p->p_comm, p->p_pid, sc.sc_cookie, + (long)scp ^ p->p_p->ps_sigcookie); + sigexit(p, SIGILL); + return (EFAULT); + } + + /* Prevent reuse of the sigcontext cookie */ + sc.sc_cookie = 0; + (void)copyout(&sc.sc_cookie, (caddr_t)scp + + offsetof(struct sigcontext, sc_cookie), + sizeof (sc.sc_cookie)); + tf = trapframe(p); sc.sc_frame.srr1 &= ~PSL_VEC; sc.sc_frame.srr1 |= (tf->srr1 & PSL_VEC); diff --git a/sys/arch/mips64/include/signal.h b/sys/arch/mips64/include/signal.h index 3dc7627d660..48534b386bd 100644 --- a/sys/arch/mips64/include/signal.h +++ b/sys/arch/mips64/include/signal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: signal.h,v 1.10 2012/12/02 07:03:31 guenther Exp $ */ +/* $OpenBSD: signal.h,v 1.11 2016/05/10 18:39:47 deraadt Exp $ */ /* * Copyright (c) 1992, 1993 @@ -56,8 +56,8 @@ typedef int sig_atomic_t; * a non-standard exit is performed. */ struct sigcontext { - long __sc_unused; - long sc_mask; /* signal mask to restore */ + long sc_cookie; + long sc_mask; /* signal mask to restore XXX should be int */ __register_t sc_pc; /* pc at time of signal */ __register_t sc_regs[32]; /* processor regs 0 to 31 */ __register_t mullo; /* mullo and mulhi registers... */ diff --git a/sys/arch/mips64/mips64/lcore_access.S b/sys/arch/mips64/mips64/lcore_access.S index 82a775862b6..e6c9a53143e 100644 --- a/sys/arch/mips64/mips64/lcore_access.S +++ b/sys/arch/mips64/mips64/lcore_access.S @@ -1,4 +1,4 @@ -/* $OpenBSD: lcore_access.S,v 1.24 2012/10/03 11:18:23 miod Exp $ */ +/* $OpenBSD: lcore_access.S,v 1.25 2016/05/10 18:39:47 deraadt Exp $ */ /* * Copyright (c) 2001-2003 Opsycon AB (www.opsycon.se / www.opsycon.com) @@ -77,6 +77,8 @@ sigcode: PTR_ADDU a0, sp, 4*REGSZ # address of sigcontext LI v0, SYS_sigreturn # sigreturn(scp) syscall + .globl _C_LABEL(sigcoderet) +_C_LABEL(sigcoderet): break 0 # just in case sigreturn fails .globl esigcode esigcode: diff --git a/sys/arch/mips64/mips64/sendsig.c b/sys/arch/mips64/mips64/sendsig.c index b022882a217..45f0ee16996 100644 --- a/sys/arch/mips64/mips64/sendsig.c +++ b/sys/arch/mips64/mips64/sendsig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sendsig.c,v 1.25 2016/03/06 19:42:27 mpi Exp $ */ +/* $OpenBSD: sendsig.c,v 1.26 2016/05/10 18:39:47 deraadt Exp $ */ /* * Copyright (c) 1990 The Regents of the University of California. @@ -164,6 +164,7 @@ sendsig(catcher, sig, mask, code, type, val) goto bail; } + ksc.sc_cookie = (long)&fp->sf_sc ^ p->p_p->ps_sigcookie; if (copyout((caddr_t)&ksc, (caddr_t)&fp->sf_sc, sizeof(ksc))) { bail: /* @@ -215,34 +216,46 @@ sys_sigreturn(p, v, retval) struct sys_sigreturn_args /* { syscallarg(struct sigcontext *) sigcntxp; } */ *uap = v; - struct sigcontext *scp; + struct sigcontext *scp = SCARG(uap, sigcntxp); struct trapframe *regs; struct sigcontext ksc; int error; - scp = SCARG(uap, sigcntxp); #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sigreturn: pid %d, scp %p\n", p->p_pid, scp); #endif regs = p->p_md.md_regs; + + if (PROC_PC(p) != p->p_p->ps_sigcoderet) { + printf("%s(%d): sigreturn not from tramp [pc 0x%lx 0x%lx]\n", + p->p_comm, p->p_pid, PROC_PC(p), p->p_p->ps_sigcoderet); + sigexit(p, SIGILL); + return (EPERM); + } + /* * Test and fetch the context structure. * We grab it all at once for speed. */ error = copyin((caddr_t)scp, (caddr_t)&ksc, sizeof(ksc)); - if (error || ksc.sc_regs[ZERO] != 0xACEDBADE) { -#ifdef DEBUG - if (!(sigdebug & SDB_FOLLOW)) - printf("sigreturn: pid %d, scp %p\n", p->p_pid, scp); - printf(" old sp %lx ra %lx pc %lx\n", - regs->sp, regs->ra, regs->pc); - printf(" new sp %lx ra %lx pc %lx err %d z %lx\n", - ksc.sc_regs[SP], ksc.sc_regs[RA], ksc.sc_regs[PC], - error, ksc.sc_regs[ZERO]); -#endif - return (EINVAL); + if (error) + return (error); + + if (ksc.sc_cookie != ((long)scp ^ p->p_p->ps_sigcookie)) { + printf("%s(%d): cookie %lx should have been %lx\n", + p->p_comm, p->p_pid, ksc.sc_cookie, + (long)scp ^ p->p_p->ps_sigcookie); + sigexit(p, SIGILL); + return (EFAULT); } + + /* Prevent reuse of the sigcontext cookie */ + ksc.sc_cookie = 0; + (void)copyout(&ksc.sc_cookie, (caddr_t)scp + + offsetof(struct sigcontext, sc_cookie), + sizeof (ksc.sc_cookie)); + scp = &ksc; /* * Restore the user supplied information diff --git a/sys/arch/powerpc/include/signal.h b/sys/arch/powerpc/include/signal.h index 7258c5a90df..67e82644ff7 100644 --- a/sys/arch/powerpc/include/signal.h +++ b/sys/arch/powerpc/include/signal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: signal.h,v 1.8 2012/12/02 07:03:31 guenther Exp $ */ +/* $OpenBSD: signal.h,v 1.9 2016/05/10 18:39:47 deraadt Exp $ */ /* $NetBSD: signal.h,v 1.1 1996/09/30 16:34:34 ws Exp $ */ /* @@ -64,7 +64,7 @@ struct trapframe { }; struct sigcontext { - int __sc_unused; + long sc_cookie; int sc_mask; /* saved signal mask */ struct trapframe sc_frame; /* saved registers */ }; diff --git a/sys/arch/sh/include/signal.h b/sys/arch/sh/include/signal.h index e5152d73cf2..24fca36829b 100644 --- a/sys/arch/sh/include/signal.h +++ b/sys/arch/sh/include/signal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: signal.h,v 1.6 2012/12/02 07:03:31 guenther Exp $ */ +/* $OpenBSD: signal.h,v 1.7 2016/05/10 18:39:47 deraadt Exp $ */ /* $NetBSD: signal.h,v 1.12 2005/12/11 12:18:58 christos Exp $ */ /* @@ -52,12 +52,12 @@ struct sigcontext { int sc_reg[21]; int sc_fpreg[34]; - int __sc_unused; + long sc_cookie; int sc_expevt; /* XXX should be above */ int sc_err; - unsigned int sc_mask; /* signal mask to restore */ + int sc_mask; /* signal mask to restore */ }; #endif /* __BSD_VISIBLE || __XPG_VISIBLE >= 420 */ diff --git a/sys/arch/sh/sh/locore_subr.S b/sys/arch/sh/sh/locore_subr.S index 82d116362d0..ec1d1e6b87f 100644 --- a/sys/arch/sh/sh/locore_subr.S +++ b/sys/arch/sh/sh/locore_subr.S @@ -1,4 +1,4 @@ -/* $OpenBSD: locore_subr.S,v 1.10 2010/09/06 08:00:31 jsg Exp $ */ +/* $OpenBSD: locore_subr.S,v 1.11 2016/05/10 18:39:47 deraadt Exp $ */ /* $NetBSD: locore_subr.S,v 1.28 2006/01/23 22:52:09 uwe Exp $ */ /* @@ -493,6 +493,8 @@ NENTRY(sigcode) mov r15, r4 /* get pointer to sigcontext */ mov.l .L_SYS_sigreturn, r0 trapa #0x80 /* and call sigreturn() */ + .globl _C_LABEL(sigcoderet) +_C_LABEL(sigcoderet): mov.l .L_SYS_exit, r0 trapa #0x80 /* exit if sigreturn fails */ /* NOTREACHED */ diff --git a/sys/arch/sh/sh/sh_machdep.c b/sys/arch/sh/sh/sh_machdep.c index b76adc05229..c07be231288 100644 --- a/sys/arch/sh/sh/sh_machdep.c +++ b/sys/arch/sh/sh/sh_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sh_machdep.c,v 1.42 2016/03/05 17:16:33 tobiasu Exp $ */ +/* $OpenBSD: sh_machdep.c,v 1.43 2016/05/10 18:39:47 deraadt Exp $ */ /* $NetBSD: sh3_machdep.c,v 1.59 2006/03/04 01:13:36 uwe Exp $ */ /* @@ -486,6 +486,8 @@ sendsig(sig_t catcher, int sig, int mask, u_long code, int type, /* frame.sf_uc.sc_err = 0; */ frame.sf_uc.sc_mask = mask; + frame.sf_uc.sc_cookie = (long)&fp->sf_uc ^ p->p_p->ps_sigcookie; +printf("cookie %lx\n", frame.sf_uc.sc_cookie); if (copyout(&frame, fp, sizeof(frame)) != 0) { /* * Process has trashed its stack; give it an illegal @@ -519,19 +521,34 @@ sys_sigreturn(struct proc *p, void *v, register_t *retval) struct sys_sigreturn_args /* { syscallarg(struct sigcontext *) sigcntxp; } */ *uap = v; - struct sigcontext *scp, context; + struct sigcontext *scp = SCARG(uap, sigcntxp), context; struct trapframe *tf; int error; - /* - * The trampoline code hands us the context. - * It is unsafe to keep track of it ourselves, in the event that a - * program jumps out of a signal handler. - */ - scp = SCARG(uap, sigcntxp); - if ((error = copyin((caddr_t)scp, &context, sizeof(*scp))) != 0) + if (PROC_PC(p) != p->p_p->ps_sigcoderet) { + printf("%s(%d): sigreturn not from sigtramp [pc 0x%x 0x%lx]\n", + p->p_comm, p->p_pid, PROC_PC(p), p->p_p->ps_sigcoderet); + sigexit(p, SIGILL); + return (EPERM); + } + + if ((error = copyin(scp, &context, sizeof(*scp))) != 0) return (error); + if (context.sc_cookie != ((long)scp ^ p->p_p->ps_sigcookie)) { + printf("%s(%d): cookie %lx should have been %lx\n", + p->p_comm, p->p_pid, context.sc_cookie, + (long)scp ^ p->p_p->ps_sigcookie); + sigexit(p, SIGILL); + return (EFAULT); + } + + /* Prevent reuse of the sigcontext cookie */ + context.sc_cookie = 0; + (void)copyout(&context.sc_cookie, (caddr_t)scp + + offsetof(struct sigcontext, sc_cookie), + sizeof (context.sc_cookie)); + /* Restore signal context. */ tf = p->p_md.md_regs; diff --git a/sys/arch/socppc/socppc/locore.S b/sys/arch/socppc/socppc/locore.S index 6184aa6a86c..38a5bb01731 100644 --- a/sys/arch/socppc/socppc/locore.S +++ b/sys/arch/socppc/socppc/locore.S @@ -1,4 +1,4 @@ -/* $OpenBSD: locore.S,v 1.20 2016/04/25 07:58:14 mpi Exp $ */ +/* $OpenBSD: locore.S,v 1.21 2016/05/10 18:39:48 deraadt Exp $ */ /* $NetBSD: locore.S,v 1.2 1996/10/16 19:33:09 ws Exp $ */ /* @@ -1269,6 +1269,8 @@ _C_LABEL(sigcode): addi %r3,%r1,((16+FPSIG_SIZEOF+15)&~0xf)+SF_SC /* compute &sf_sc */ li %r0,SYS_sigreturn sc /* sigreturn(scp) */ + .globl _C_LABEL(sigcoderet) +_C_LABEL(sigcoderet): li %r0,SYS_exit sc /* exit(errno) */ _C_LABEL(esigcode): diff --git a/sys/arch/socppc/socppc/machdep.c b/sys/arch/socppc/socppc/machdep.c index bfed97cc704..38dad7dc79a 100644 --- a/sys/arch/socppc/socppc/machdep.c +++ b/sys/arch/socppc/socppc/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.65 2016/03/03 02:42:16 bmercer Exp $ */ +/* $OpenBSD: machdep.c,v 1.66 2016/05/10 18:39:48 deraadt Exp $ */ /* $NetBSD: machdep.c,v 1.4 1996/10/16 19:33:11 ws Exp $ */ /* @@ -508,6 +508,7 @@ sendsig(sig_t catcher, int sig, int mask, u_long code, int type, frame.sf_sip = &fp->sf_si; initsiginfo(&frame.sf_si, sig, code, type, val); } + frame.sf_sc.sc_cookie = (long)fp ^ p->p_p->ps_sigcookie; if (copyout(&frame, fp, sizeof frame) != 0) sigexit(p, SIGILL); @@ -535,12 +536,34 @@ sys_sigreturn(struct proc *p, void *v, register_t *retval) struct sys_sigreturn_args /* { syscallarg(struct sigcontext *) sigcntxp; } */ *uap = v; - struct sigcontext sc; + struct sigcontext sc, *scp = SCARG(uap, sigcntxp); struct trapframe *tf; int error; - if ((error = copyin(SCARG(uap, sigcntxp), &sc, sizeof sc))) + if (PROC_PC(p) != p->p_p->ps_sigcoderet) { + printf("%s(%d): sigreturn not from tramp [pc 0x%x 0x%lx]\n", + p->p_comm, p->p_pid, PROC_PC(p), p->p_p->ps_sigcoderet); + sigexit(p, SIGILL); + return (EPERM); + } + + if ((error = copyin(scp, &sc, sizeof sc))) return error; + + if (sc.sc_cookie != ((long)scp ^ p->p_p->ps_sigcookie)) { + printf("%s(%d): cookie %lx should have been %lx\n", + p->p_comm, p->p_pid, sc.sc_cookie, + (long)scp ^ p->p_p->ps_sigcookie); + sigexit(p, SIGILL); + return (EFAULT); + } + + /* Prevent reuse of the sigcontext cookie */ + sc.sc_cookie = 0; + (void)copyout(&sc.sc_cookie, (caddr_t)scp + + offsetof(struct sigcontext, sc_cookie), + sizeof (sc.sc_cookie)); + tf = trapframe(p); if ((sc.sc_frame.srr1 & PSL_USERSTATIC) != (tf->srr1 & PSL_USERSTATIC)) return EINVAL; diff --git a/sys/arch/sparc/include/signal.h b/sys/arch/sparc/include/signal.h index 2c50cd06314..ed1d6819801 100644 --- a/sys/arch/sparc/include/signal.h +++ b/sys/arch/sparc/include/signal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: signal.h,v 1.11 2013/04/01 17:18:20 deraadt Exp $ */ +/* $OpenBSD: signal.h,v 1.12 2016/05/10 18:39:48 deraadt Exp $ */ /* $NetBSD: signal.h,v 1.4 1996/02/01 22:32:35 mycroft Exp $ */ /* @@ -58,7 +58,7 @@ typedef int sig_atomic_t; * a non-standard exit is performed. */ struct sigcontext { - int __sc_unused; + long sc_cookie; int sc_mask; /* signal mask to restore */ /* begin machine dependent portion */ int sc_sp; /* %sp to restore */ diff --git a/sys/arch/sparc/sparc/machdep.c b/sys/arch/sparc/sparc/machdep.c index 9d663ab4595..139b0d449c0 100644 --- a/sys/arch/sparc/sparc/machdep.c +++ b/sys/arch/sparc/sparc/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.175 2015/10/21 07:59:18 mpi Exp $ */ +/* $OpenBSD: machdep.c,v 1.176 2016/05/10 18:39:48 deraadt Exp $ */ /* $NetBSD: machdep.c,v 1.85 1997/09/12 08:55:02 pk Exp $ */ /* @@ -432,7 +432,7 @@ sendsig(catcher, sig, mask, code, type, val) */ newsp = (int)fp - sizeof(struct rwindow); write_user_windows(); - /* XXX do not copyout siginfo if not needed */ + sf.sf_sc.sc_cookie = (long)fp ^ p->p_p->ps_sigcookie; if (rwindow_save(p) || copyout((caddr_t)&sf, (caddr_t)fp, sizeof sf) || copyout(&oldsp, &((struct rwindow *)newsp)->rw_in[6], sizeof(register_t)) != 0) { @@ -486,7 +486,7 @@ sys_sigreturn(p, v, retval) struct sys_sigreturn_args /* { syscallarg(struct sigcontext *) sigcntxp; } */ *uap = v; - struct sigcontext ksc; + struct sigcontext ksc, *sc = SCARG(uap, sigcntxp); struct trapframe *tf; int error; @@ -499,8 +499,30 @@ sys_sigreturn(p, v, retval) printf("sigreturn: %s[%d], sigcntxp %p\n", p->p_comm, p->p_pid, SCARG(uap, sigcntxp)); #endif - if ((error = copyin(SCARG(uap, sigcntxp), &ksc, sizeof(ksc))) != 0) + if (PROC_PC(p) != p->p_p->ps_sigcoderet) { + printf("%s(%d): sigreturn not from tramp [pc 0x%lx 0x%lx]\n", + p->p_comm, p->p_pid, PROC_PC(p), p->p_p->ps_sigcoderet); + sigexit(p, SIGILL); + return (EPERM); + } + + if ((error = copyin(sc, &ksc, sizeof(ksc))) != 0) return (error); + + if (ksc.sc_cookie != ((long)scp ^ p->p_p->ps_sigcookie)) { + printf("%s(%d): cookie %lx should have been %lx\n", + p->p_comm, p->p_pid, ksc.sc_cookie, + (long)scp ^ p->p_p->ps_sigcookie); + sigexit(p, SIGILL); + return (EFAULT); + } + + /* Prevent reuse of the sigcontext cookie */ + ksc.sc_cookie = 0; + (void)copyout(&ksc.sc_cookie, (caddr_t)scp + + offsetof(struct sigcontext, sc_cookie), + sizeof (ksc.sc_cookie)); + tf = p->p_md.md_tf; /* * Only the icc bits in the psr are used, so it need not be diff --git a/sys/arch/sparc64/include/signal.h b/sys/arch/sparc64/include/signal.h index b5a2122f72e..3a9cc69b870 100644 --- a/sys/arch/sparc64/include/signal.h +++ b/sys/arch/sparc64/include/signal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: signal.h,v 1.11 2013/04/01 17:18:20 deraadt Exp $ */ +/* $OpenBSD: signal.h,v 1.12 2016/05/10 18:39:48 deraadt Exp $ */ /* $NetBSD: signal.h,v 1.10 2001/05/09 19:50:49 kleink Exp $ */ /* @@ -58,8 +58,7 @@ typedef int sig_atomic_t; * a non-standard exit is performed. */ struct sigcontext { - int __sc_unused; - int __sc_mask13; /* signal mask to restore (old style) */ + long sc_cookie; /* begin machine dependent portion */ long sc_sp; /* %sp to restore */ long sc_pc; /* pc to restore */ @@ -67,7 +66,7 @@ struct sigcontext { long sc_tstate; /* tstate to restore */ long sc_g1; /* %g1 to restore */ long sc_o0; /* %o0 to restore */ - int sc_mask; /* signal mask to restore (new style) */ + int sc_mask; /* signal mask to restore */ }; #endif /* __BSD_VISIBLE || __XPG_VISIBLE >= 420 */ #endif /* _LOCORE */ diff --git a/sys/arch/sparc64/sparc64/locore.s b/sys/arch/sparc64/sparc64/locore.s index 2933bb6c378..b1a8a1d9dca 100644 --- a/sys/arch/sparc64/sparc64/locore.s +++ b/sys/arch/sparc64/sparc64/locore.s @@ -1,4 +1,4 @@ -/* $OpenBSD: locore.s,v 1.181 2015/08/28 23:28:39 kettenis Exp $ */ +/* $OpenBSD: locore.s,v 1.182 2016/05/10 18:39:49 deraadt Exp $ */ /* $NetBSD: locore.s,v 1.137 2001/08/13 06:10:10 jdolecek Exp $ */ /* @@ -5429,6 +5429,8 @@ _C_LABEL(sigcode): restore %g0, SYS_sigreturn, %g1 ! get registers back & set syscall # add %sp, BIAS + 128 + 16, %o0 ! compute scp ! andn %o0, 0x0f, %o0 + .globl _C_LABEL(sigcoderet) +_C_LABEL(sigcoderet): t ST_SYSCALL ! sigreturn(scp) ! sigreturn does not return unless it fails mov SYS_exit, %g1 ! exit(errno) diff --git a/sys/arch/sparc64/sparc64/machdep.c b/sys/arch/sparc64/sparc64/machdep.c index af20f427e13..e2a94b6fb10 100644 --- a/sys/arch/sparc64/sparc64/machdep.c +++ b/sys/arch/sparc64/sparc64/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.175 2016/03/07 13:21:51 naddy Exp $ */ +/* $OpenBSD: machdep.c,v 1.176 2016/05/10 18:39:49 deraadt Exp $ */ /* $NetBSD: machdep.c,v 1.108 2001/07/24 19:30:14 eeh Exp $ */ /*- @@ -492,7 +492,7 @@ sendsig(catcher, sig, mask, code, type, val) newsp = (vaddr_t)fp - sizeof(struct rwindow); write_user_windows(); - /* XXX do not copyout siginfo if not needed */ + sf.sf_sc.sc_cookie = (long)&fp->sf_sc ^ p->p_p->ps_sigcookie; if (rwindow_save(p) || copyout((caddr_t)&sf, (caddr_t)fp, sizeof sf) || CPOUTREG(&(((struct rwindow *)newsp)->rw_in[6]), tf->tf_out[6])) { /* @@ -544,10 +544,18 @@ sys_sigreturn(p, v, retval) struct sys_sigreturn_args /* { syscallarg(struct sigcontext *) sigcntxp; } */ *uap = v; - struct sigcontext sc, *scp; + struct sigcontext *scp = SCARG(uap, sigcntxp), ksc; struct trapframe64 *tf; int error = EINVAL; + if (PROC_PC(p) != p->p_p->ps_sigcoderet) { + printf("%s(%d): sigreturn not from tramp [pc 0x%llx 0x%lx]\n", + p->p_comm, p->p_pid, PROC_PC(p), + p->p_p->ps_sigcoderet); + sigexit(p, SIGILL); + return (EPERM); + } + /* First ensure consistent stack state (see sendsig). */ write_user_windows(); @@ -558,15 +566,27 @@ sys_sigreturn(p, v, retval) #endif sigexit(p, SIGILL); } - scp = SCARG(uap, sigcntxp); - if ((vaddr_t)scp & 3 || - (error = copyin((caddr_t)scp, &sc, sizeof sc)) != 0) { -#ifdef DEBUG - printf("sigreturn: copyin failed: scp=%p\n", scp); -#endif + + if ((vaddr_t)scp & 3) + return (EINVAL); + if ((error = copyin((caddr_t)scp, &ksc, sizeof ksc))) return (error); + + if (ksc.sc_cookie != ((long)scp ^ p->p_p->ps_sigcookie)) { + printf("%s(%d): cookie %lx should have been %lx\n", + p->p_comm, p->p_pid, ksc.sc_cookie, + (long)scp ^ p->p_p->ps_sigcookie); + sigexit(p, SIGILL); + return (EFAULT); } - scp = ≻ + + /* Prevent reuse of the sigcontext cookie */ + ksc.sc_cookie = 0; + (void)copyout(&ksc.sc_cookie, (caddr_t)scp + + offsetof(struct sigcontext, sc_cookie), + sizeof (ksc.sc_cookie)); + + scp = &ksc; tf = p->p_md.md_tf; /* @@ -574,12 +594,12 @@ sys_sigreturn(p, v, retval) * verified. pc and npc must be multiples of 4. This is all * that is required; if it holds, just do it. */ - if (((sc.sc_pc | sc.sc_npc) & 3) != 0 || - (sc.sc_pc == 0) || (sc.sc_npc == 0)) { + if (((ksc.sc_pc | ksc.sc_npc) & 3) != 0 || + (ksc.sc_pc == 0) || (ksc.sc_npc == 0)) { #ifdef DEBUG printf("sigreturn: pc %p or npc %p invalid\n", - (void *)(unsigned long)sc.sc_pc, - (void *)(unsigned long)sc.sc_npc); + (void *)(unsigned long)ksc.sc_pc, + (void *)(unsigned long)ksc.sc_npc); #endif return (EINVAL); } |