This is the first demonstration of a mitigation against SROP.

This is SROP:  http://www.cs.vu.nl/~herbertb/papers/srop_sp14.pdf

A solution for Linux was attempted (https://lwn.net/Articles/674861),
but that proposal appears to have run lightly into the ABI wall, and
seems to not be integrated.

Antoine did some experimental ports builds using diffs I provided
during p2k16.  As a result, I eventually realized how far we can push
things for now (and what we could do later).  Early on (like the lwn
article above), I though a HMAC-like construct would be needed; but it
appears it is not.

Utilizing a trick from kbind(2), the kernel now only accepts signal
returns from the PC address of the sigreturn(2) syscall in the signal
trampoline.  Since the signal trampoline page is randomized placed per
process, it is only known by directly returning from a signal handler.

As well, the sigcontext provided to sigreturn(2) now contains a magic
cookie constructed from a per-process cookie XOR'd against the address
of the signal context.  That part is similar to the LWN discussion
mentioned above.  I came to the same conclusion semi-independently as
a result of Antoine's ports builds, which identified all the parts of
the application software ecosystem I had to study.  Woe is me!

These two changes together make it largely impossible for a sigcontext
to be constructed manually, and then passed to the kernel to act upon.

sigreturn(2) becomes a highly difficult gadget to use; the setup
required to utilize it means the attacker probably already has
sufficient codeflow control that they don't need to utilize
sigreturn(2).

To make the PC tracking trick work, sigreturn() provision from libc
will die.  This is not a standard-mandated function, it is simply a
back-end piece of code to make signals actually work right.  A few
longjmp-style routines in libc on some architectures abused
sigreturn() have been fixed.  syscall(SYS_sigreturn) also becomes
illegal.  The process is killed if either the cookie or the PC are
wrong.

So far, this is running on amd64 i386 macppc sparc64 hppa sgi loongson
and alpha.  On sparc64, alpha, and mips64 machines, make sure your
libc and static binaries are up-to-date with a very new snapshot.

This is just a draft.

Index: arch/alpha/alpha/machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/alpha/alpha/machdep.c,v
retrieving revision 1.171
diff -u -p -u -r1.171 machdep.c
--- arch/alpha/alpha/machdep.c  21 Oct 2015 07:59:17 -0000      1.171
+++ arch/alpha/alpha/machdep.c  29 Apr 2016 13:17:40 -0000
@@ -1477,6 +1477,7 @@ sendsig(catcher, sig, mask, code, type, 
        } else
                sip = NULL;
 
+       ksc.sc_cookie = scp ^ p->p_p->ps_sigcookie;
        /*
         * copy the frame out to userland.
         */
@@ -1542,9 +1543,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,12 +1551,32 @@ sys_sigreturn(p, v, retval)
            printf("sigreturn: pid %d, scp %p\n", p->p_pid, scp);
 #endif
 
+       if (PROC_PC(p) != (u_int64_t)p->p_p->ps_sigcode +
+           (p->p_p->ps_emul->e_esigret - p->p_p->ps_emul->e_sigcode)) {
+               printf("%s(%d): sigreturn not from sigtramp [pc 0x%llu]\n",
+                   p->p_comm, p->p_pid, PROC_PC(p));
+               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 long)scp ^ p->p_p->ps_sigcookie)) {
+               printf("%s(%d): cookie %8lx should have been %8lx\n",
+                   p->p_comm, p->p_pid, ksc.sc_cookie, (long)scp);
+               return (EFAULT);
+       }
+
+       if (ksc.sc_cookie != ((long long)scp ^ p->p_p->ps_sigcookie)) {
+               printf("%s(%d): cookie %8lx should have been %8lx\n",
+                   p->p_comm, p->p_pid, ksc.sc_cookie, (long)scp);
+               return (EFAULT);
+       }
 
        if (ksc.sc_regs[R_ZERO] != 0xACEDBADE)          /* magic number */
                return (EINVAL);
Index: arch/alpha/include/signal.h
===================================================================
RCS file: /cvs/src/sys/arch/alpha/include/signal.h,v
retrieving revision 1.9
diff -u -p -u -r1.9 signal.h
--- arch/alpha/include/signal.h 7 Nov 2015 19:06:05 -0000       1.9
+++ arch/alpha/include/signal.h 8 May 2016 14:05:16 -0000
@@ -48,7 +48,7 @@ typedef int   sig_atomic_t;
  */
 struct  sigcontext {
        long    __sc_unused;
-       long    sc_mask;                /* signal mask to restore */
+       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) */
Index: arch/amd64/amd64/locore.S
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/locore.S,v
retrieving revision 1.76
diff -u -p -u -r1.76 locore.S
--- arch/amd64/amd64/locore.S   26 Feb 2016 02:23:07 -0000      1.76
+++ arch/amd64/amd64/locore.S   29 Apr 2016 11:30:11 -0000
@@ -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)
Index: arch/amd64/amd64/machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/machdep.c,v
retrieving revision 1.218
diff -u -p -u -r1.218 machdep.c
--- arch/amd64/amd64/machdep.c  3 Apr 2016 17:48:33 -0000       1.218
+++ arch/amd64/amd64/machdep.c  29 Apr 2016 13:24:11 -0000
@@ -571,6 +571,7 @@ sendsig(sig_t catcher, int sig, int mask
        }
        scp = sp - sss;
 
+       ksc.sc_cookie = scp ^ p->p_p->ps_sigcookie;
        if (copyout(&ksc, (void *)scp, sizeof(ksc)))
                sigexit(p, SIGILL);
 
@@ -611,17 +612,31 @@ sys_sigreturn(struct proc *p, void *v, r
        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) != (u_int64_t)p->p_p->ps_sigcoderet) {
+               printf("%s(%d): sigreturn not from sigtramp [pc 0x%llu]\n",
+                   p->p_comm, p->p_pid, PROC_PC(p));
+               sigexit(p, SIGILL);
+               return (EPERM);
+       }
+
        if ((error = copyin((caddr_t)scp, &ksc, sizeof ksc)))
                return (error);
+
+       if (ksc.sc_cookie != ((long long)scp ^ p->p_p->ps_sigcookie)) {
+               printf("%s(%d): cookie %8lx should have been %8lx\n",
+                   p->p_comm, p->p_pid, ksc.sc_cookie, (long)scp);
+               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))
Index: arch/amd64/include/signal.h
===================================================================
RCS file: /cvs/src/sys/arch/amd64/include/signal.h,v
retrieving revision 1.8
diff -u -p -u -r1.8 signal.h
--- arch/amd64/include/signal.h 1 Apr 2013 17:18:19 -0000       1.8
+++ arch/amd64/include/signal.h 8 May 2016 14:02:07 -0000
@@ -81,7 +81,7 @@ struct sigcontext {
        long    sc_ss;
 
        struct fxsave64 *sc_fpstate;
-       int     __sc_unused;
+       long    sc_cookie;
        int     sc_mask;
 };
 #endif /* __BSD_VISIBLE || __XPG_VISIBLE >= 420 */
Index: arch/arm/arm/sig_machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/arm/arm/sig_machdep.c,v
retrieving revision 1.12
diff -u -p -u -r1.12 sig_machdep.c
--- arch/arm/arm/sig_machdep.c  31 Jan 2016 00:14:50 -0000      1.12
+++ arch/arm/arm/sig_machdep.c  29 Apr 2016 13:06:47 -0000
@@ -136,6 +136,7 @@ sendsig(sig_t catcher, int sig, int retu
                initsiginfo(&frame.sf_si, sig, code, type, val);
        }
 
+       frame.sf_sc.sc_cookie = fp ^ p->p_p->ps_sigcookie;
        if (copyout(&frame, fp, sizeof(frame)) != 0) {
                /*
                 * Process has trashed its stack; give it an illegal
@@ -182,23 +183,31 @@ sys_sigreturn(struct proc *p, void *v, r
        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)
-               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 (PROC_PC(p) != (u_int64_t)p->p_p->ps_sigcode +
+           (p->p_p->ps_emul->e_esigret - p->p_p->ps_emul->e_sigcode)) {
+               printf("%s(%d): sigreturn not from sigtramp [pc 0x%llu]\n",
+                   p->p_comm, p->p_pid, PROC_PC(p));
+               sigexit(p, SIGILL);
+               return (EPERM);
+       }
+
        if (copyin((caddr_t)scp, &context, sizeof(*scp)) != 0)
                return (EFAULT);
+
+       if (ksc.sc_cookie != ((long long)scp ^ p->p_p->ps_sigcookie)) {
+               printf("%s(%d): cookie %8lx should have been %8lx\n",
+                   p->p_comm, p->p_pid, ksc.sc_cookie, (long)scp);
+               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));
 
        /*
         * Make sure the processor mode has not been tampered with and
Index: arch/arm/arm/sigcode.S
===================================================================
RCS file: /cvs/src/sys/arch/arm/arm/sigcode.S,v
retrieving revision 1.2
diff -u -p -u -r1.2 sigcode.S
--- arch/arm/arm/sigcode.S      27 Dec 2006 17:49:26 -0000      1.2
+++ arch/arm/arm/sigcode.S      29 Apr 2016 09:42:45 -0000
@@ -52,6 +52,8 @@ ENTRY_NP(sigcode)
        add     r0, sp, #SIGF_SC
        ldr     r12, =SYS_sigreturn
        swi     SYS_sigreturn
+       .globl  _C_LABEL(sigcode_sigreturn)
+_C_LABEL(sigcode_sigreturn):
 
 /* Well if that failed we better exit quick ! */
 
Index: arch/arm/include/signal.h
===================================================================
RCS file: /cvs/src/sys/arch/arm/include/signal.h,v
retrieving revision 1.8
diff -u -p -u -r1.8 signal.h
--- arch/arm/include/signal.h   2 Dec 2012 07:03:31 -0000       1.8
+++ arch/arm/include/signal.h   29 Apr 2016 08:38:34 -0000
@@ -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;
Index: arch/hppa/hppa/locore.S
===================================================================
RCS file: /cvs/src/sys/arch/hppa/hppa/locore.S,v
retrieving revision 1.193
diff -u -p -u -r1.193 locore.S
--- arch/hppa/hppa/locore.S     23 Oct 2014 16:57:45 -0000      1.193
+++ arch/hppa/hppa/locore.S     29 Apr 2016 09:42:33 -0000
@@ -3040,6 +3040,8 @@ sigcode_call
        ldil    L%SYSCALLGATE, r1
        copy    r4, arg0
        .call
+       .globl  _C_LABEL(sigcode_sigreturn)
+_C_LABEL(sigcode_sigreturn):
        ble     4(sr7, r1)
        ldi     SYS_sigreturn, t1
 
Index: arch/hppa/hppa/machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/hppa/hppa/machdep.c,v
retrieving revision 1.243
diff -u -p -u -r1.243 machdep.c
--- arch/hppa/hppa/machdep.c    20 Apr 2016 23:52:04 -0000      1.243
+++ arch/hppa/hppa/machdep.c    29 Apr 2016 12:56:01 -0000
@@ -1303,6 +1303,7 @@ sendsig(sig_t catcher, int sig, int mask
                    p->p_pid, sig, scp, ksc.sc_fp, tf->tf_sp);
 #endif
 
+       ksc.sc_cookie = scp ^ p->p_p->ps_sigcookie;
        if (copyout(&ksc, (void *)scp, sizeof(ksc)))
                sigexit(p, SIGILL);
 
@@ -1329,11 +1330,31 @@ sys_sigreturn(struct proc *p, void *v, r
        struct trapframe *tf = p->p_md.md_regs;
        int error;
 
+       if (PROC_PC(p) != (u_int64_t)p->p_p->ps_sigcode +
+           (p->p_p->ps_emul->e_esigret - p->p_p->ps_emul->e_sigcode)) {
+               printf("%s(%d): sigreturn not from sigtramp [pc 0x%llu]\n",
+                   p->p_comm, p->p_pid, PROC_PC(p));
+               sigexit(p, SIGILL);
+               return (EPERM);
+       }
+
        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 (ksc.sc_cookie != ((long long)scp ^ p->p_p->ps_sigcookie)) {
+               printf("%s(%d): cookie %8lx should have been %8lx\n",
+                   p->p_comm, p->p_pid, ksc.sc_cookie, (long)scp);
+               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));
 
        /* Flush the FPU context first. */
        fpu_proc_flush(p);
Index: arch/hppa/include/signal.h
===================================================================
RCS file: /cvs/src/sys/arch/hppa/include/signal.h,v
retrieving revision 1.11
diff -u -p -u -r1.11 signal.h
--- arch/hppa/include/signal.h  1 Apr 2013 17:18:20 -0000       1.11
+++ arch/hppa/include/signal.h  8 May 2016 14:04:42 -0000
@@ -47,15 +47,15 @@ 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 */
-       unsigned long   sc_ps;          /* psl to restore */
-       unsigned long   sc_fp;          /* fp to restore */
-       unsigned long   sc_pcoqh;       /* pc offset queue (head) to restore */
-       unsigned long   sc_pcoqt;       /* pc offset queue (tail) to restore */
-       unsigned long   sc_resv[2];
-       unsigned long   sc_regs[32];
-       unsigned long   sc_fpregs[64];
+       long    sc_cookie;
+       long    sc_mask;        /* signal mask to restore XXX should be int */
+       u_long  sc_ps;          /* psl to restore */
+       u_long  sc_fp;          /* fp to restore */
+       u_long  sc_pcoqh;       /* pc offset queue (head) to restore */
+       u_long  sc_pcoqt;       /* pc offset queue (tail) to restore */
+       u_long  sc_resv[2];
+       u_long  sc_regs[32];
+       u_long  sc_fpregs[64];
 };
 #endif /* __BSD_VISIBLE || __XPG_VISIBLE >= 420 */
 #endif  /* !_MACHINE_SIGNAL_H_ */
Index: arch/hppa64/hppa64/locore.S
===================================================================
RCS file: /cvs/src/sys/arch/hppa64/hppa64/locore.S,v
retrieving revision 1.41
diff -u -p -u -r1.41 locore.S
--- arch/hppa64/hppa64/locore.S 12 Oct 2011 18:30:09 -0000      1.41
+++ arch/hppa64/hppa64/locore.S 29 Apr 2016 09:42:29 -0000
@@ -1968,6 +1968,8 @@ ENTRY(sigcode,0)
        depd    %r0, 31, 32, %r1
        copy    %r4, %arg0
        .call
+       .globl  _C_LABEL(sigcode_sigreturn)
+_C_LABEL(sigcode_sigreturn):
        ble     4(%sr7, %r1)
        ldi     SYS_sigreturn, %r1
 
Index: arch/hppa64/hppa64/machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/hppa64/hppa64/machdep.c,v
retrieving revision 1.79
diff -u -p -u -r1.79 machdep.c
--- arch/hppa64/hppa64/machdep.c        20 Apr 2016 23:52:04 -0000      1.79
+++ arch/hppa64/hppa64/machdep.c        29 Apr 2016 13:04:16 -0000
@@ -900,6 +900,7 @@ sendsig(sig_t catcher, int sig, int mask
                    p->p_pid, sig, scp, ksc.sc_fp, tf->tf_sp);
 #endif
 
+       ksc.sc_cookie = scp ^ p->p_p->ps_sigcookie;
        if (copyout(&ksc, (void *)scp, sizeof(ksc)))
                sigexit(p, SIGILL);
 
@@ -922,21 +923,35 @@ sys_sigreturn(struct proc *p, void *v, r
        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) != (u_int64_t)p->p_p->ps_sigcode +
+           (p->p_p->ps_emul->e_esigret - p->p_p->ps_emul->e_sigcode)) {
+               printf("%s(%d): sigreturn not from sigtramp [pc 0x%llu]\n",
+                   p->p_comm, p->p_pid, PROC_PC(p));
+               sigexit(p, SIGILL);
+               return (EPERM);
+       }
 
        /* flush the FPU ctx first */
        fpu_proc_flush(p);
 
        if ((error = copyin((caddr_t)scp, (caddr_t)&ksc, sizeof ksc)))
                return (error);
+
+       if (ksc.sc_cookie != ((long long)scp ^ p->p_p->ps_sigcookie)) {
+               printf("%s(%d): cookie %8lx should have been %8lx\n",
+                   p->p_comm, p->p_pid, ksc.sc_cookie, (long)scp);
+               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)
Index: arch/hppa64/include/signal.h
===================================================================
RCS file: /cvs/src/sys/arch/hppa64/include/signal.h,v
retrieving revision 1.6
diff -u -p -u -r1.6 signal.h
--- arch/hppa64/include/signal.h        1 Apr 2013 17:18:20 -0000       1.6
+++ arch/hppa64/include/signal.h        8 May 2016 14:04:20 -0000
@@ -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_cookie;
+       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 */
Index: arch/i386/i386/locore.s
===================================================================
RCS file: /cvs/src/sys/arch/i386/i386/locore.s,v
retrieving revision 1.167
diff -u -p -u -r1.167 locore.s
--- arch/i386/i386/locore.s     15 Mar 2016 03:17:51 -0000      1.167
+++ arch/i386/i386/locore.s     28 Apr 2016 13:11:24 -0000
@@ -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(sigcode_sigreturn)
+_C_LABEL(sigcode_sigreturn):
        movl    $SYS_exit,%eax
        int     $0x80                   # exit if sigreturn fails
        .globl  _C_LABEL(esigcode)
Index: arch/i386/i386/machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/i386/machdep.c,v
retrieving revision 1.583
diff -u -p -u -r1.583 machdep.c
--- arch/i386/i386/machdep.c    24 Mar 2016 04:56:08 -0000      1.583
+++ arch/i386/i386/machdep.c    29 Apr 2016 13:03:21 -0000
@@ -2440,6 +2440,7 @@ sendsig(sig_t catcher, int sig, int mask
        }
 
        /* XXX don't copyout siginfo if not needed? */
+       frame.sf_sc.sc_cookie = fp ^ p->p_p->ps_sigcookie;
        if (copyout(&frame, fp, sizeof(frame)) != 0) {
                /*
                 * Process has trashed its stack; give it an illegal
@@ -2479,18 +2480,32 @@ sys_sigreturn(struct proc *p, void *v, r
        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) != (u_int32_t)p->p_p->ps_sigcode +
+           (p->p_p->ps_emul->e_esigret - p->p_p->ps_emul->e_sigcode)) {
+               printf("%s(%d): sigreturn from non-tramp location [pc 0x%lu]\n",
+                   p->p_comm, p->p_pid, PROC_PC(p));
+               sigexit(p, SIGILL);
+               return (EPERM);
+       }
+
+       if (error = copyin((caddr_t)scp, &context, sizeof(*scp)))
+               return (error);
+
+       if (ksc.sc_cookie != ((long long)scp ^ p->p_p->ps_sigcookie)) {
+               printf("%s(%d): cookie %8lx should have been %8lx\n",
+                   p->p_comm, p->p_pid, ksc.sc_cookie, (long)scp);
                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));
 
        /*
         * Restore signal context.
Index: arch/i386/include/signal.h
===================================================================
RCS file: /cvs/src/sys/arch/i386/include/signal.h,v
retrieving revision 1.10
diff -u -p -u -r1.10 signal.h
--- arch/i386/include/signal.h  1 Apr 2013 17:18:20 -0000       1.10
+++ arch/i386/include/signal.h  29 Apr 2016 08:34:59 -0000
@@ -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 */
Index: arch/m88k/m88k/sig_machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/m88k/m88k/sig_machdep.c,v
retrieving revision 1.23
diff -u -p -u -r1.23 sig_machdep.c
--- arch/m88k/m88k/sig_machdep.c        9 Feb 2015 08:48:23 -0000       1.23
+++ arch/m88k/m88k/sig_machdep.c        29 Apr 2016 13:02:27 -0000
@@ -207,18 +207,34 @@ sys_sigreturn(struct proc *p, void *v, r
        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) != (u_int64_t)p->p_p->ps_sigcode +
+           (p->p_p->ps_emul->e_esigret - p->p_p->ps_emul->e_sigcode)) {
+               printf("%s(%d): sigreturn not from sigtramp [pc 0x%llu]\n",
+                   p->p_comm, p->p_pid, PROC_PC(p));
+               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 long)scp ^ p->p_p->ps_sigcookie)) {
+               printf("%s(%d): cookie %8lx should have been %8lx\n",
+                   p->p_comm, p->p_pid, ksc.sc_cookie, (long)scp);
+               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;
Index: arch/m88k/m88k/subr.S
===================================================================
RCS file: /cvs/src/sys/arch/m88k/m88k/subr.S,v
retrieving revision 1.24
diff -u -p -u -r1.24 subr.S
--- arch/m88k/m88k/subr.S       8 Jun 2014 13:20:39 -0000       1.24
+++ arch/m88k/m88k/subr.S       29 Apr 2016 09:42:18 -0000
@@ -1087,6 +1087,8 @@ ENTRY(sigcode)                    /* r31 points to sigfra
        ld      %r2,  %r31, 0   /* pick sigcontext* */
        or      %r13, %r0,  SYS_sigreturn
        tb0     0,    %r0,  450 /* syscall trap, calling sigreturn */
+       .globl  _C_LABEL(sigcode_sigreturn)
+_C_LABEL(sigcode_sigreturn):
        NOP                     | failure return
 #ifdef dontbother              /* sigreturn will not return unless it fails */
        NOP                     | success return
Index: arch/macppc/macppc/locore.S
===================================================================
RCS file: /cvs/src/sys/arch/macppc/macppc/locore.S,v
retrieving revision 1.53
diff -u -p -u -r1.53 locore.S
--- arch/macppc/macppc/locore.S 25 Apr 2016 07:58:14 -0000      1.53
+++ arch/macppc/macppc/locore.S 29 Apr 2016 09:41:53 -0000
@@ -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(sigcode_sigreturn)
+_C_LABEL(sigcode_sigreturn):
        li      %r0,SYS_exit
        sc                              /* exit(errno) */
 _C_LABEL(esigcode):
Index: arch/macppc/macppc/machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/macppc/macppc/machdep.c,v
retrieving revision 1.173
diff -u -p -u -r1.173 machdep.c
--- arch/macppc/macppc/machdep.c        20 Apr 2016 23:52:04 -0000      1.173
+++ arch/macppc/macppc/machdep.c        29 Apr 2016 13:01:05 -0000
@@ -481,6 +481,7 @@ sendsig(sig_t catcher, int sig, int mask
                frame.sf_sip = &fp->sf_si;
                initsiginfo(&frame.sf_si, sig, code, type, val);
        }
+       frame.sc_sc.sc_cookie = fp ^ p->p_p->ps_sigcookie;
        if (copyout(&frame, fp, sizeof frame) != 0)
                sigexit(p, SIGILL);
 
@@ -512,8 +513,29 @@ sys_sigreturn(struct proc *p, void *v, r
        struct trapframe *tf;
        int error;
 
+       if (PROC_PC(p) != (u_int64_t)p->p_p->ps_sigcode +
+           (p->p_p->ps_emul->e_esigret - p->p_p->ps_emul->e_sigcode)) {
+               printf("%s(%d): sigreturn not from sigtramp [pc 0x%llu]\n",
+                   p->p_comm, p->p_pid, PROC_PC(p));
+               sigexit(p, SIGILL);
+               return (EPERM);
+       }
+
        if ((error = copyin(SCARG(uap, sigcntxp), &sc, sizeof sc)))
                return error;
+
+       if (ksc.sc_cookie != ((long long)scp ^ p->p_p->ps_sigcookie)) {
+               printf("%s(%d): cookie %8lx should have been %8lx\n",
+                   p->p_comm, p->p_pid, ksc.sc_cookie, (long)scp);
+               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 = trapframe(p);
        sc.sc_frame.srr1 &= ~PSL_VEC;
        sc.sc_frame.srr1 |= (tf->srr1 & PSL_VEC);
Index: arch/mips64/include/signal.h
===================================================================
RCS file: /cvs/src/sys/arch/mips64/include/signal.h,v
retrieving revision 1.10
diff -u -p -u -r1.10 signal.h
--- arch/mips64/include/signal.h        2 Dec 2012 07:03:31 -0000       1.10
+++ arch/mips64/include/signal.h        8 May 2016 14:03:47 -0000
@@ -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... */
Index: arch/mips64/mips64/lcore_access.S
===================================================================
RCS file: /cvs/src/sys/arch/mips64/mips64/lcore_access.S,v
retrieving revision 1.24
diff -u -p -u -r1.24 lcore_access.S
--- arch/mips64/mips64/lcore_access.S   3 Oct 2012 11:18:23 -0000       1.24
+++ arch/mips64/mips64/lcore_access.S   29 Apr 2016 09:41:47 -0000
@@ -77,6 +77,8 @@ sigcode:
        PTR_ADDU a0, sp, 4*REGSZ                # address of sigcontext
        LI      v0, SYS_sigreturn       # sigreturn(scp)
        syscall
+       .globl  _C_LABEL(sigcode_sigreturn)
+_C_LABEL(sigcode_sigreturn):
        break   0                       # just in case sigreturn fails
        .globl  esigcode
 esigcode:
Index: arch/mips64/mips64/sendsig.c
===================================================================
RCS file: /cvs/src/sys/arch/mips64/mips64/sendsig.c,v
retrieving revision 1.25
diff -u -p -u -r1.25 sendsig.c
--- arch/mips64/mips64/sendsig.c        6 Mar 2016 19:42:27 -0000       1.25
+++ arch/mips64/mips64/sendsig.c        29 Apr 2016 13:00:16 -0000
@@ -164,6 +164,7 @@ sendsig(catcher, sig, mask, code, type, 
                        goto bail;
        }
 
+       sf.sf_sc.sc_cookie = (caddr_t)&fp->sf_sc ^ p->p_p->ps_sigcookie;
        if (copyout((caddr_t)&ksc, (caddr_t)&fp->sf_sc, sizeof(ksc))) {
 bail:
                /*
@@ -215,34 +216,45 @@ 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) != (u_int64_t)p->p_p->ps_sigcode +
+           (p->p_p->ps_emul->e_esigret - p->p_p->ps_emul->e_sigcode)) {
+               printf("%s(%d): sigreturn not from sigtramp [pc 0x%llu]\n",
+                   p->p_comm, p->p_pid, PROC_PC(p));
+               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 long)scp ^ p->p_p->ps_sigcookie)) {
+               printf("%s(%d): cookie %8lx should have been %8lx\n",
+                   p->p_comm, p->p_pid, ksc.sc_cookie, (long)scp);
+               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
Index: arch/powerpc/include/signal.h
===================================================================
RCS file: /cvs/src/sys/arch/powerpc/include/signal.h,v
retrieving revision 1.8
diff -u -p -u -r1.8 signal.h
--- arch/powerpc/include/signal.h       2 Dec 2012 07:03:31 -0000       1.8
+++ arch/powerpc/include/signal.h       29 Apr 2016 08:33:27 -0000
@@ -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 */
 };
Index: arch/sh/include/signal.h
===================================================================
RCS file: /cvs/src/sys/arch/sh/include/signal.h,v
retrieving revision 1.6
diff -u -p -u -r1.6 signal.h
--- arch/sh/include/signal.h    2 Dec 2012 07:03:31 -0000       1.6
+++ arch/sh/include/signal.h    8 May 2016 14:02:49 -0000
@@ -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 */
Index: arch/sh/sh/locore_subr.S
===================================================================
RCS file: /cvs/src/sys/arch/sh/sh/locore_subr.S,v
retrieving revision 1.10
diff -u -p -u -r1.10 locore_subr.S
--- arch/sh/sh/locore_subr.S    6 Sep 2010 08:00:31 -0000       1.10
+++ arch/sh/sh/locore_subr.S    29 Apr 2016 09:41:36 -0000
@@ -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(sigcode_sigreturn)
+_C_LABEL(sigcode_sigreturn):
        mov.l   .L_SYS_exit, r0
        trapa   #0x80                   /* exit if sigreturn fails */
        /* NOTREACHED */
Index: arch/sh/sh/sh_machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/sh/sh/sh_machdep.c,v
retrieving revision 1.42
diff -u -p -u -r1.42 sh_machdep.c
--- arch/sh/sh/sh_machdep.c     5 Mar 2016 17:16:33 -0000       1.42
+++ arch/sh/sh/sh_machdep.c     29 Apr 2016 12:58:44 -0000
@@ -486,6 +486,7 @@ sendsig(sig_t catcher, int sig, int mask
        /* frame.sf_uc.sc_err = 0; */
        frame.sf_uc.sc_mask = mask;
 
+       frame.sf_uc.sc_cookie = fp ^ p->p_p->ps_sigcookie;
        if (copyout(&frame, fp, sizeof(frame)) != 0) {
                /*
                 * Process has trashed its stack; give it an illegal
@@ -519,18 +520,32 @@ sys_sigreturn(struct proc *p, void *v, r
        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 (PROC_PC(p) != (u_int64_t)p->p_p->ps_sigcode +
+           (p->p_p->ps_emul->e_esigret - p->p_p->ps_emul->e_sigcode)) {
+               printf("%s(%d): sigreturn not from sigtramp [pc 0x%llu]\n",
+                   p->p_comm, p->p_pid, PROC_PC(p));
+               sigexit(p, SIGILL);
+               return (EPERM);
+       }
+
        if ((error = copyin((caddr_t)scp, &context, sizeof(*scp))) != 0)
                return (error);
+
+       if (ksc.sc_cookie != ((long long)scp ^ p->p_p->ps_sigcookie)) {
+               printf("%s(%d): cookie %8lx should have been %8lx\n",
+                   p->p_comm, p->p_pid, ksc.sc_cookie, (long)scp);
+               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));
 
        /* Restore signal context. */
        tf = p->p_md.md_regs;
Index: arch/socppc/socppc/locore.S
===================================================================
RCS file: /cvs/src/sys/arch/socppc/socppc/locore.S,v
retrieving revision 1.20
diff -u -p -u -r1.20 locore.S
--- arch/socppc/socppc/locore.S 25 Apr 2016 07:58:14 -0000      1.20
+++ arch/socppc/socppc/locore.S 29 Apr 2016 09:41:28 -0000
@@ -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(sigcode_sigreturn)
+_C_LABEL(sigcode_sigreturn):
        li      %r0,SYS_exit
        sc                              /* exit(errno) */
 _C_LABEL(esigcode):
Index: arch/socppc/socppc/machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/socppc/socppc/machdep.c,v
retrieving revision 1.65
diff -u -p -u -r1.65 machdep.c
--- arch/socppc/socppc/machdep.c        3 Mar 2016 02:42:16 -0000       1.65
+++ arch/socppc/socppc/machdep.c        29 Apr 2016 12:57:25 -0000
@@ -508,6 +508,7 @@ sendsig(sig_t catcher, int sig, int mask
                frame.sf_sip = &fp->sf_si;
                initsiginfo(&frame.sf_si, sig, code, type, val);
        }
+       frame.sf_sc.sc_cookie = fp ^ p->p_p->ps_sigcookie;
        if (copyout(&frame, fp, sizeof frame) != 0)
                sigexit(p, SIGILL);
 
@@ -539,8 +540,30 @@ sys_sigreturn(struct proc *p, void *v, r
        struct trapframe *tf;
        int error;
 
+       if (PROC_PC(p) != (u_int64_t)p->p_p->ps_sigcode +
+           (p->p_p->ps_emul->e_esigret - p->p_p->ps_emul->e_sigcode)) {
+               printf("%s(%d): sigreturn not from sigtramp [pc 0x%llu]\n",
+                   p->p_comm, p->p_pid, PROC_PC(p));
+               sigexit(p, SIGILL);
+               return (EPERM);
+       }
+
        if ((error = copyin(SCARG(uap, sigcntxp), &sc, sizeof sc)))
                return error;
+
+       if (ksc.sc_cookie != ((long long)scp ^ p->p_p->ps_sigcookie)) {
+               printf("%s(%d): cookie %8lx should have been %8lx\n",
+                   p->p_comm, p->p_pid, ksc.sc_cookie, (long)scp);
+               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 = trapframe(p);
        if ((sc.sc_frame.srr1 & PSL_USERSTATIC) != (tf->srr1 & PSL_USERSTATIC))
                return EINVAL;
Index: arch/sparc/include/signal.h
===================================================================
RCS file: /cvs/src/sys/arch/sparc/include/signal.h,v
retrieving revision 1.11
diff -u -p -u -r1.11 signal.h
--- arch/sparc/include/signal.h 1 Apr 2013 17:18:20 -0000       1.11
+++ arch/sparc/include/signal.h 29 Apr 2016 08:36:22 -0000
@@ -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 */
Index: arch/sparc/sparc/machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/sparc/sparc/machdep.c,v
retrieving revision 1.175
diff -u -p -u -r1.175 machdep.c
--- arch/sparc/sparc/machdep.c  21 Oct 2015 07:59:18 -0000      1.175
+++ arch/sparc/sparc/machdep.c  29 Apr 2016 12:55:39 -0000
@@ -432,7 +432,7 @@ sendsig(catcher, sig, mask, code, type, 
         */
        newsp = (int)fp - sizeof(struct rwindow);
        write_user_windows();
-       /* XXX do not copyout siginfo if not needed */
+       sf.sf_sc.sc_cookie = 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) {
@@ -499,6 +499,15 @@ sys_sigreturn(p, v, retval)
                printf("sigreturn: %s[%d], sigcntxp %p\n",
                    p->p_comm, p->p_pid, SCARG(uap, sigcntxp));
 #endif
+       if (PROC_PC(p) != p->p_p->ps_sigcode +
+           (p->p_p->ps_emul->e_esigret - p->p_p->ps_emul->e_sigcode)) {
+               printf("%s(%d): sigreturn from non-tramp location [pc 0x%lu]\n",
+                   p->p_comm, p->p_pid, PROC_PC(p));
+               sigexit(p, SIGILL);
+               return (EPERM);
+       }
+
+
        if ((error = copyin(SCARG(uap, sigcntxp), &ksc, sizeof(ksc))) != 0)
                return (error);
        tf = p->p_md.md_tf;
Index: arch/sparc64/include/signal.h
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/include/signal.h,v
retrieving revision 1.11
diff -u -p -u -r1.11 signal.h
--- arch/sparc64/include/signal.h       1 Apr 2013 17:18:20 -0000       1.11
+++ arch/sparc64/include/signal.h       29 Apr 2016 08:24:30 -0000
@@ -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 */
Index: arch/sparc64/sparc64/machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/sparc64/machdep.c,v
retrieving revision 1.175
diff -u -p -u -r1.175 machdep.c
--- arch/sparc64/sparc64/machdep.c      7 Mar 2016 13:21:51 -0000       1.175
+++ arch/sparc64/sparc64/machdep.c      29 Apr 2016 13:30:40 -0000
@@ -492,7 +492,7 @@ sendsig(catcher, sig, mask, code, type, 
        newsp = (vaddr_t)fp - sizeof(struct rwindow);
        write_user_windows();
 
-       /* XXX do not copyout siginfo if not needed */
+       sf.sf_sc.sc_cookie = fp ^ 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) != (u_int64_t)p->p_p->ps_sigcode +
+           (p->p_p->ps_emul->e_esigret - p->p_p->ps_emul->e_sigcode)) {
+               printf("%s(%d): sigreturn from non-tramp location [pc 0x%lu]\n",
+                   p->p_comm, p->p_pid, PROC_PC(p));
+               sigexit(p, SIGILL);
+               return (EPERM);
+       }
+
        /* First ensure consistent stack state (see sendsig). */
        write_user_windows();
 
@@ -558,15 +566,25 @@ 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 long)scp ^ p->p_p->ps_sigcookie)) {
+               printf("%s(%d): cookie %8lx should have been %8lx\n",
+                   p->p_comm, p->p_pid, ksc.sc_cookie, (long)scp);
+               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;
        /*
Index: kern/exec_elf.c
===================================================================
RCS file: /cvs/src/sys/kern/exec_elf.c,v
retrieving revision 1.120
diff -u -p -u -r1.120 exec_elf.c
--- kern/exec_elf.c     28 Feb 2016 15:46:18 -0000      1.120
+++ kern/exec_elf.c     29 Apr 2016 11:30:28 -0000
@@ -108,7 +108,7 @@ void ELFNAME(load_psection)(struct exec_
        Elf_Phdr *, Elf_Addr *, Elf_Addr *, int *, int);
 int ELFNAMEEND(coredump)(struct proc *, void *);
 
-extern char sigcode[], esigcode[];
+extern char sigcode[], esigcode[], sigcoderet[];
 #ifdef SYSCALL_DEBUG
 extern char *syscallnames[];
 #endif
@@ -145,6 +145,7 @@ struct emul ELFNAMEEND(emul) = {
        ELFNAMEEND(coredump),
        sigcode,
        esigcode,
+       sigcoderet,
        EMUL_ENABLED | EMUL_NATIVE,
 };
 
Index: kern/init_main.c
===================================================================
RCS file: /cvs/src/sys/kern/init_main.c,v
retrieving revision 1.250
diff -u -p -u -r1.250 init_main.c
--- kern/init_main.c    3 May 2016 14:52:39 -0000       1.250
+++ kern/init_main.c    8 May 2016 14:07:04 -0000
@@ -144,7 +144,7 @@ void        kqueue_init(void);
 void   taskq_init(void);
 void   pool_gc_pages(void *);
 
-extern char sigcode[], esigcode[];
+extern char sigcode[], esigcode[], sigcoderet[];
 #ifdef SYSCALL_DEBUG
 extern char *syscallnames[];
 #endif
@@ -168,6 +168,7 @@ struct emul emul_native = {
        NULL,           /* coredump */
        sigcode,
        esigcode,
+       sigcoderet,
        EMUL_ENABLED | EMUL_NATIVE,
 };
 
Index: kern/kern_exec.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_exec.c,v
retrieving revision 1.176
diff -u -p -u -r1.176 kern_exec.c
--- kern/kern_exec.c    25 Apr 2016 20:00:33 -0000      1.176
+++ kern/kern_exec.c    29 Apr 2016 13:24:54 -0000
@@ -498,6 +498,7 @@ sys_execve(struct proc *p, void *v, regi
        TCB_SET(p, NULL);       /* reset the TCB address */
        pr->ps_kbind_addr = 0;  /* reset the kbind bits */
        pr->ps_kbind_cookie = 0;
+       arc4random_buf(&pr->ps_sigcookie, sizeof pr->ps_sigcookie);
 
        /* set command name & other accounting info */
        memset(p->p_comm, 0, sizeof(p->p_comm));
@@ -867,6 +868,8 @@ exec_sigcode_map(struct process *pr, str
                uao_detach(e->e_sigobject);
                return (ENOMEM);
        }
+       pr->ps_sigcoderet = pr->ps_sigcode +
+           (pr->ps_emul->e_esigret - pr->ps_emul->e_sigcode);
 
        return (0);
 }
Index: sys/proc.h
===================================================================
RCS file: /cvs/src/sys/sys/proc.h,v
retrieving revision 1.219
diff -u -p -u -r1.219 proc.h
--- sys/proc.h  25 Apr 2016 20:18:31 -0000      1.219
+++ sys/proc.h  29 Apr 2016 13:23:47 -0000
@@ -107,6 +107,7 @@ struct      emul {
        int     (*e_coredump)(struct proc *, void *cookie);
        char    *e_sigcode;             /* Start of sigcode */
        char    *e_esigcode;            /* End of sigcode */
+       char    *e_esigret;             /* sigaction RET position */
        int     e_flags;                /* Flags, see below */
        struct uvm_object *e_sigobject; /* shared sigcode object */
                                        /* Per-process hooks */
@@ -200,6 +201,7 @@ struct process {
        vaddr_t ps_strings;             /* User pointers to argv/env */
        vaddr_t ps_stackgap;            /* User pointer to the "stackgap" */
        vaddr_t ps_sigcode;             /* User pointer to the signal code */
+       vaddr_t ps_sigcoderet;          /* User pointer to sigreturn retPC */
        u_int   ps_rtableid;            /* Process routing table/domain. */
        char    ps_nice;                /* Process "nice" value. */
 
@@ -216,6 +218,7 @@ struct process {
        struct whitepaths *ps_pledgepaths;
 
        int64_t ps_kbind_cookie;
+       int64_t ps_sigcookie;
        u_long  ps_kbind_addr;
 
 /* End area that is copied on creation. */

Reply via email to