diff options
26 files changed, 1870 insertions, 489 deletions
diff --git a/sys/alpha/alpha/machdep.c b/sys/alpha/alpha/machdep.c index 66eb675..dcb6e63 100644 --- a/sys/alpha/alpha/machdep.c +++ b/sys/alpha/alpha/machdep.c @@ -138,6 +138,7 @@ #include <alpha/alpha/db_instruction.h> #include <sys/vnode.h> #include <miscfs/procfs/procfs.h> +#include <machine/sigframe.h> #ifdef SYSVSHM #include <sys/shm.h> @@ -1161,11 +1162,11 @@ DELAY(int n) * frame pointer, it returns to the user * specified pc, psl. */ -void -sendsig(sig_t catcher, int sig, int mask, u_long code) +static void +osendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) { struct proc *p = curproc; - siginfo_t *sip, ksi; + osiginfo_t *sip, ksi; struct trapframe *frame; struct sigacts *psp = p->p_sigacts; int oonstack, fsize, rndfsize; @@ -1174,6 +1175,7 @@ sendsig(sig_t catcher, int sig, int mask, u_long code) oonstack = psp->ps_sigstk.ss_flags & SS_ONSTACK; fsize = sizeof ksi; rndfsize = ((fsize + 15) / 16) * 16; + /* * Allocate and validate space for the signal handler * context. Note that if the stack is in P0 space, the @@ -1182,33 +1184,23 @@ sendsig(sig_t catcher, int sig, int mask, u_long code) * the space with a `brk'. */ if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack && - (psp->ps_sigonstack & sigmask(sig))) { - sip = (siginfo_t *)((caddr_t)psp->ps_sigstk.ss_sp + + SIGISMEMBER(psp->ps_sigonstack, sig)) { + sip = (osiginfo_t *)((caddr_t)psp->ps_sigstk.ss_sp + psp->ps_sigstk.ss_size - rndfsize); psp->ps_sigstk.ss_flags |= SS_ONSTACK; } else - sip = (siginfo_t *)(alpha_pal_rdusp() - rndfsize); + sip = (osiginfo_t *)(alpha_pal_rdusp() - rndfsize); + (void)grow_stack(p, (u_long)sip); -#ifdef DEBUG - if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) - printf("sendsig(%d): sig %d ssp %p usp %p\n", p->p_pid, - sig, &oonstack, sip); -#endif if (useracc((caddr_t)sip, fsize, B_WRITE) == 0) { -#ifdef DEBUG - if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) - printf("sendsig(%d): useracc failed on sig %d\n", - p->p_pid, sig); -#endif /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ - SIGACTION(p, SIGILL) = SIG_DFL; - sig = sigmask(SIGILL); - p->p_sigignore &= ~sig; - p->p_sigcatch &= ~sig; - p->p_sigmask &= ~sig; + SIGACTION(p, SIGILL) = SIG_DFL; + SIGDELSET(p->p_sigignore, SIGILL); + SIGDELSET(p->p_sigcatch, SIGILL); + SIGDELSET(p->p_sigmask, SIGILL); psignal(p, SIGILL); return; } @@ -1217,7 +1209,7 @@ sendsig(sig_t catcher, int sig, int mask, u_long code) * Build the signal context to be used by sigreturn. */ ksi.si_sc.sc_onstack = oonstack; - ksi.si_sc.sc_mask = mask; + SIG2OSIG(*mask, ksi.si_sc.sc_mask); ksi.si_sc.sc_pc = frame->tf_regs[FRAME_PC]; ksi.si_sc.sc_ps = frame->tf_regs[FRAME_PS]; @@ -1251,6 +1243,105 @@ sendsig(sig_t catcher, int sig, int mask, u_long code) ksi.si_code = code; ksi.si_value.sigval_ptr = NULL; /* XXX */ + /* + * copy the frame out to userland. + */ + (void) copyout((caddr_t)&ksi, (caddr_t)sip, fsize); + + /* + * Set up the registers to return to sigcode. + */ + frame->tf_regs[FRAME_PC] = PS_STRINGS - (esigcode - sigcode); + frame->tf_regs[FRAME_A0] = sig; + if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) + frame->tf_regs[FRAME_A1] = (u_int64_t)sip; + else + frame->tf_regs[FRAME_A1] = code; + frame->tf_regs[FRAME_A2] = (u_int64_t)&sip->si_sc; + frame->tf_regs[FRAME_T12] = (u_int64_t)catcher; /* t12 is pv */ + alpha_pal_wrusp((unsigned long)sip); +} + +void +sendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) +{ + struct proc *p; + struct trapframe *frame; + struct sigacts *psp; + struct sigframe sf, *sfp; + int rndfsize; + + p = curproc; + + if ((p->p_flag & P_NEWSIGSET) == 0) { + osendsig(catcher, sig, mask, code); + return; + } + + frame = p->p_md.md_tf; + psp = p->p_sigacts; + rndfsize = ((sizeof(sf) + 15) / 16) * 16; + + /* save user context */ + bzero(&sf, sizeof(struct sigframe)); + sf.sf_uc.uc_sigmask = *mask; + sf.sf_uc.uc_stack = psp->ps_sigstk; + sf.sf_uc.uc_mcontext.mc_tf = *frame; + + /* + * Allocate and validate space for the signal handler + * context. Note that if the stack is in P0 space, the + * call to grow() is a nop, and the useracc() check + * will fail if the process has not already allocated + * the space with a `brk'. + */ + if ((psp->ps_flags & SAS_ALTSTACK) != 0 && + (psp->ps_sigstk.ss_flags & SS_ONSTACK) == 0 && + SIGISMEMBER(psp->ps_sigonstack, sig)) { + sfp = (struct sigframe *)((caddr_t)psp->ps_sigstk.ss_sp + + psp->ps_sigstk.ss_size - rndfsize); + psp->ps_sigstk.ss_flags |= SS_ONSTACK; + } else + sfp = (struct sigframe *)(alpha_pal_rdusp() - rndfsize); + + (void)grow_stack(p, (u_long)sfp); +#ifdef DEBUG + if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) + printf("sendsig(%d): sig %d ssp %p usp %p\n", p->p_pid, + sig, &sf, sfp); +#endif + if (useracc((caddr_t)sfp, sizeof(sf), B_WRITE) == 0) { +#ifdef DEBUG + if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) + printf("sendsig(%d): useracc failed on sig %d\n", + p->p_pid, sig); +#endif + /* + * Process has trashed its stack; give it an illegal + * instruction to halt it in its tracks. + */ + SIGACTION(p, SIGILL) = SIG_DFL; + SIGDELSET(p->p_sigignore, SIGILL); + SIGDELSET(p->p_sigcatch, SIGILL); + SIGDELSET(p->p_sigmask, SIGILL); + psignal(p, SIGILL); + return; + } + + sf.sf_uc.uc_mcontext.mc_tf.tf_regs[FRAME_SP] = alpha_pal_rdusp(); + + /* save the floating-point state, if necessary, then copy it. */ + if (p == fpcurproc) { + alpha_pal_wrfen(1); + savefpstate(&p->p_addr->u_pcb.pcb_fp); + alpha_pal_wrfen(0); + fpcurproc = NULL; + } + sf.sf_uc.uc_mcontext.mc_ownedfp = p->p_md.md_flags & MDP_FPUSED; + bcopy(&p->p_addr->u_pcb.pcb_fp, + (struct fpreg *)sf.sf_uc.uc_mcontext.mc_fpregs, + sizeof(struct fpreg)); + sf.sf_uc.uc_mcontext.mc_fp_control = p->p_addr->u_pcb.pcb_fp_control; #ifdef COMPAT_OSF1 /* @@ -1261,11 +1352,11 @@ sendsig(sig_t catcher, int sig, int mask, u_long code) /* * copy the frame out to userland. */ - (void) copyout((caddr_t)&ksi, (caddr_t)sip, fsize); + (void) copyout((caddr_t)&sf, (caddr_t)sfp, sizeof(sf)); #ifdef DEBUG if (sigdebug & SDB_FOLLOW) - printf("sendsig(%d): sig %d sip %p code %lx\n", p->p_pid, sig, - sip, code); + printf("sendsig(%d): sig %d sfp %p code %lx\n", p->p_pid, sig, + sfp, code); #endif /* @@ -1273,13 +1364,19 @@ sendsig(sig_t catcher, int sig, int mask, u_long code) */ frame->tf_regs[FRAME_PC] = PS_STRINGS - (esigcode - sigcode); frame->tf_regs[FRAME_A0] = sig; - if (p->p_sigacts->ps_siginfo & sigmask(sig)) - frame->tf_regs[FRAME_A1] = (u_int64_t)sip; + if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { + frame->tf_regs[FRAME_A1] = (u_int64_t)&(sfp->sf_si); + + /* Fill in POSIX parts */ + sf.sf_si.si_signo = sig; + sf.sf_si.si_code = code; + } else frame->tf_regs[FRAME_A1] = code; - frame->tf_regs[FRAME_A2] = (u_int64_t)&sip->si_sc; + + frame->tf_regs[FRAME_A2] = (u_int64_t)&(sfp->sf_uc); frame->tf_regs[FRAME_T12] = (u_int64_t)catcher; /* t12 is pv */ - alpha_pal_wrusp((unsigned long)sip); + alpha_pal_wrusp((unsigned long)sfp); #ifdef DEBUG if (sigdebug & SDB_FOLLOW) @@ -1301,19 +1398,14 @@ sendsig(sig_t catcher, int sig, int mask, u_long code) * state to gain improper privileges. */ int -sigreturn(struct proc *p, - struct sigreturn_args /* { - struct sigcontext *sigcntxp; - } */ *uap) +osigreturn(struct proc *p, + struct osigreturn_args /* { + struct osigcontext *sigcntxp; + } */ *uap) { - struct sigcontext *scp, ksc; + struct osigcontext *scp, ksc; scp = uap->sigcntxp; -#ifdef DEBUG - if (sigdebug & SDB_FOLLOW) - printf("sigreturn: pid %d, scp %p\n", p->p_pid, scp); -#endif - if (ALIGN(scp) != (u_int64_t)scp) return (EINVAL); @@ -1334,7 +1426,18 @@ sigreturn(struct proc *p, p->p_sigacts->ps_sigstk.ss_flags |= SS_ONSTACK; else p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK; - p->p_sigmask = ksc.sc_mask &~ sigcantmask; + + /* + * longjmp is still implemented by calling osigreturn. The new + * sigmask is stored in sc_reserved, sc_mask is only used for + * backward compatibility. + */ + if ((p->p_flag & P_NEWSIGSET) == 0) { + OSIG2SIG(ksc.sc_mask, p->p_sigmask); + } + else + p->p_sigmask = *((sigset_t *)(&ksc.sc_reserved[0])); + SIG_CANTMASK(p->p_sigmask); set_regs(p, (struct reg *)ksc.sc_regs); p->p_md.md_tf->tf_regs[FRAME_PC] = ksc.sc_pc; @@ -1349,6 +1452,60 @@ sigreturn(struct proc *p, bcopy((struct fpreg *)ksc.sc_fpregs, &p->p_addr->u_pcb.pcb_fp, sizeof(struct fpreg)); p->p_addr->u_pcb.pcb_fp_control = ksc.sc_fp_control; + return (EJUSTRETURN); +} + +int +sigreturn(struct proc *p, + struct sigreturn_args /* { + ucontext_t *sigcntxp; + } */ *uap) +{ + ucontext_t uc, *ucp; + struct pcb *pcb; + + ucp = uap->sigcntxp; + + if ((p->p_flag & P_NEWSIGSET) == 0) + return (osigreturn(p, (struct osigreturn_args *)uap)); + + pcb = &p->p_addr->u_pcb; + +#ifdef DEBUG + if (sigdebug & SDB_FOLLOW) + printf("sigreturn: pid %d, scp %p\n", p->p_pid, ucp); +#endif + + if (ALIGN(ucp) != (u_int64_t)ucp) + return (EINVAL); + + /* + * Test and fetch the context structure. + * We grab it all at once for speed. + */ + if (useracc((caddr_t)ucp, sizeof(ucontext_t), B_WRITE) == 0 || + copyin((caddr_t)ucp, (caddr_t)&uc, sizeof(ucontext_t))) + return (EINVAL); + + /* + * Restore the user-supplied information + */ + *p->p_md.md_tf = uc.uc_mcontext.mc_tf; + p->p_md.md_tf->tf_regs[FRAME_PS] |= ALPHA_PSL_USERSET; + p->p_md.md_tf->tf_regs[FRAME_PS] &= ~ALPHA_PSL_USERCLR; + pcb->pcb_hw.apcb_usp = p->p_md.md_tf->tf_regs[FRAME_SP]; + alpha_pal_wrusp(pcb->pcb_hw.apcb_usp); + + p->p_sigacts->ps_sigstk = uc.uc_stack; + p->p_sigmask = uc.uc_sigmask; + SIG_CANTMASK(p->p_sigmask); + + /* XXX ksc.sc_ownedfp ? */ + if (p == fpcurproc) + fpcurproc = NULL; + bcopy((struct fpreg *)uc.uc_mcontext.mc_fpregs, + &p->p_addr->u_pcb.pcb_fp, sizeof(struct fpreg)); + p->p_addr->u_pcb.pcb_fp_control = uc.uc_mcontext.mc_fp_control; #ifdef DEBUG if (sigdebug & SDB_FOLLOW) diff --git a/sys/alpha/include/sigframe.h b/sys/alpha/include/sigframe.h new file mode 100644 index 0000000..bc445a9 --- /dev/null +++ b/sys/alpha/include/sigframe.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 1999 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_SIGFRAME_H_ +#define _MACHINE_SIGFRAME_H_ 1 + +struct osigframe { + struct osigcontext sf_sc; + osiginfo_t sf_si; +}; + +struct sigframe { + unsigned long __spare__; + ucontext_t sf_uc; + siginfo_t sf_si; +}; + +#endif /* _MACHINE_SIGFRAME_H_ */ diff --git a/sys/alpha/include/signal.h b/sys/alpha/include/signal.h index 07eaba1..90a5a39 100644 --- a/sys/alpha/include/signal.h +++ b/sys/alpha/include/signal.h @@ -32,8 +32,8 @@ #define _ALPHA_SIGNAL_H_ typedef long sig_atomic_t; - #ifndef _ANSI_SOURCE + /* * Information pushed on stack when a signal is delivered. * This is used by the kernel to restore state following @@ -44,7 +44,9 @@ typedef long sig_atomic_t; * Note that sc_regs[] and sc_fpregs[]+sc_fpcr are inline * representations of 'struct reg' and 'struct fpreg', respectively. */ -struct sigcontext { +typedef unsigned int osigset_t; + +struct osigcontext { long sc_onstack; /* sigstack state to restore */ long sc_mask; /* signal mask to restore */ long sc_pc; /* pc to restore */ diff --git a/sys/alpha/include/ucontext.h b/sys/alpha/include/ucontext.h new file mode 100644 index 0000000..66b9e51 --- /dev/null +++ b/sys/alpha/include/ucontext.h @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 1999 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_UCONTEXT_H_ +#define _MACHINE_UCONTEXT_H_ 1 + +#include <machine/frame.h> + +typedef struct { + struct trapframe mc_tf; + unsigned long mc_fpregs[32]; + unsigned long mc_fpcr; + unsigned long mc_fp_control; + unsigned long mc_apcb_usp; + long mc_ownedfp; + long __spare__[8]; +} mcontext_t; + +#endif /* _MACHINE_UCONTEXT_H_ */ diff --git a/sys/amd64/amd64/genassym.c b/sys/amd64/amd64/genassym.c index d4023cc..62dbf53 100644 --- a/sys/amd64/amd64/genassym.c +++ b/sys/amd64/amd64/genassym.c @@ -72,6 +72,8 @@ #include <machine/globaldata.h> #include <machine/vm86.h> +#include <machine/sigframe.h> + #define OS(s, m) ((u_int)offsetof(struct s, m)) int main __P((void)); @@ -147,10 +149,16 @@ main() printf("#define\tTF_EFLAGS %#x\n", OS(trapframe, tf_eflags)); printf("#define\tSIGF_HANDLER %#x\n", OS(sigframe, sf_ahu.sf_handler)); - printf("#define\tSIGF_SC %#x\n", OS(sigframe, sf_siginfo.si_sc)); - printf("#define\tSC_PS %#x\n", OS(sigcontext, sc_ps)); - printf("#define\tSC_FS %#x\n", OS(sigcontext, sc_fs)); - printf("#define\tSC_GS %#x\n", OS(sigcontext, sc_gs)); + printf("#define\tSIGF_SIGRET %#x\n", OS(sigframe, sf_sigreturn)); + printf("#define\tSIGF_SC %#x\n", OS(osigframe, sf_siginfo.si_sc)); + printf("#define\tSIGF_UC %#x\n", OS(sigframe, sf_uc)); + + printf("#define\tSC_PS %#x\n", OS(osigcontext, sc_ps)); + printf("#define\tSC_FS %#x\n", OS(osigcontext, sc_fs)); + printf("#define\tSC_GS %#x\n", OS(osigcontext, sc_gs)); + + printf("#define\tUC_EFLAGS %#x\n", OS(__ucontext, uc_mcontext.mc_tf.tf_eflags)); + printf("#define\tUC_GS %#x\n", OS(__ucontext, uc_mcontext.mc_gs)); printf("#define\tB_READ %#x\n", B_READ); printf("#define\tENOENT %d\n", ENOENT); diff --git a/sys/amd64/amd64/locore.S b/sys/amd64/amd64/locore.S index ad499bd..e87c275 100644 --- a/sys/amd64/amd64/locore.S +++ b/sys/amd64/amd64/locore.S @@ -414,18 +414,38 @@ NON_GPROF_ENTRY(prepare_usermode) * Signal trampoline, copied to top of user stack */ NON_GPROF_ENTRY(sigcode) - call SIGF_HANDLER(%esp) - lea SIGF_SC(%esp),%eax /* scp (the call may have clobbered the */ - /* copy at 8(%esp)) */ + call SIGF_HANDLER(%esp) /* call signal handler */ + movl SIGF_SIGRET(%esp),%eax /* Get sigreturn cookie */ + cmpl $0x0ABCDEF0,%eax /* New one? */ + jne 3f +/* New signalling code */ + lea SIGF_UC(%esp),%eax /* get ucontext */ pushl %eax - pushl %eax /* junk to fake return address */ - testl $PSL_VM,SC_PS(%eax) + testl $PSL_VM,UC_EFLAGS(%eax) jne 1f - movl SC_GS(%eax),%gs /* restore %gs */ + movl UC_GS(%eax),%gs /* restore %gs */ 1: - movl $SYS_sigreturn,%eax /* sigreturn() */ - int $0x80 /* enter kernel with args on stack */ -2: jmp 2b + movl $SYS_sigreturn,%eax + pushl %eax /* junk to fake return addr. */ + int $0x80 /* enter kernel with args */ + /* on stack */ +2: + jmp 2b +/* Old signalling code */ +3: + lea SIGF_SC(%esp),%eax /* get sigcontext */ + pushl %eax + testl $PSL_VM,SC_PS(%eax) + jne 4f + movl SC_GS(%eax),%gs /* restore %gs */ +4: + movl $SYS_osigreturn,%eax + pushl %eax /* junk to fake return addr. */ + int $0x80 /* enter kernel with args */ + /* on stack */ +5: + jmp 5b + ALIGN_TEXT _esigcode: diff --git a/sys/amd64/amd64/locore.s b/sys/amd64/amd64/locore.s index ad499bd..e87c275 100644 --- a/sys/amd64/amd64/locore.s +++ b/sys/amd64/amd64/locore.s @@ -414,18 +414,38 @@ NON_GPROF_ENTRY(prepare_usermode) * Signal trampoline, copied to top of user stack */ NON_GPROF_ENTRY(sigcode) - call SIGF_HANDLER(%esp) - lea SIGF_SC(%esp),%eax /* scp (the call may have clobbered the */ - /* copy at 8(%esp)) */ + call SIGF_HANDLER(%esp) /* call signal handler */ + movl SIGF_SIGRET(%esp),%eax /* Get sigreturn cookie */ + cmpl $0x0ABCDEF0,%eax /* New one? */ + jne 3f +/* New signalling code */ + lea SIGF_UC(%esp),%eax /* get ucontext */ pushl %eax - pushl %eax /* junk to fake return address */ - testl $PSL_VM,SC_PS(%eax) + testl $PSL_VM,UC_EFLAGS(%eax) jne 1f - movl SC_GS(%eax),%gs /* restore %gs */ + movl UC_GS(%eax),%gs /* restore %gs */ 1: - movl $SYS_sigreturn,%eax /* sigreturn() */ - int $0x80 /* enter kernel with args on stack */ -2: jmp 2b + movl $SYS_sigreturn,%eax + pushl %eax /* junk to fake return addr. */ + int $0x80 /* enter kernel with args */ + /* on stack */ +2: + jmp 2b +/* Old signalling code */ +3: + lea SIGF_SC(%esp),%eax /* get sigcontext */ + pushl %eax + testl $PSL_VM,SC_PS(%eax) + jne 4f + movl SC_GS(%eax),%gs /* restore %gs */ +4: + movl $SYS_osigreturn,%eax + pushl %eax /* junk to fake return addr. */ + int $0x80 /* enter kernel with args */ + /* on stack */ +5: + jmp 5b + ALIGN_TEXT _esigcode: diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index 7b712d2..b5280c6 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -127,6 +127,7 @@ #include <machine/vm86.h> #include <machine/random.h> #include <sys/ptrace.h> +#include <machine/sigframe.h> extern void init386 __P((int first)); extern void dblfault_handler __P((void)); @@ -471,79 +472,66 @@ netisr_sysinit(data) * frame pointer, it returns to the user * specified pc, psl. */ -void -sendsig(catcher, sig, mask, code) - sig_t catcher; - int sig, mask; - u_long code; +static void +osendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) { register struct proc *p = curproc; register struct trapframe *regs; - register struct sigframe *fp; - struct sigframe sf; + register struct osigframe *fp; + struct osigframe sf; struct sigacts *psp = p->p_sigacts; int oonstack; regs = p->p_md.md_regs; - oonstack = psp->ps_sigstk.ss_flags & SS_ONSTACK; - /* - * Allocate and validate space for the signal handler context. - */ - if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack && - (psp->ps_sigonstack & sigmask(sig))) { - fp = (struct sigframe *)(psp->ps_sigstk.ss_sp + - psp->ps_sigstk.ss_size - sizeof(struct sigframe)); + oonstack = (psp->ps_sigstk.ss_flags & SS_ONSTACK) ? 1 : 0; + + /* Allocate and validate space for the signal handler context. */ + if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack && + SIGISMEMBER(psp->ps_sigonstack, sig)) { + fp = (struct osigframe *)(psp->ps_sigstk.ss_sp + + psp->ps_sigstk.ss_size - sizeof(struct osigframe)); psp->ps_sigstk.ss_flags |= SS_ONSTACK; - } else { - fp = (struct sigframe *)regs->tf_esp - 1; } + else + fp = (struct osigframe *)regs->tf_esp - 1; /* * grow() will return FALSE if the fp will not fit inside the stack * and the stack can not be grown. useracc will return FALSE * if access is denied. */ - if ((grow_stack (p, (int)fp) == FALSE) || - (useracc((caddr_t)fp, sizeof(struct sigframe), B_WRITE) == FALSE)) { + if (grow_stack(p, (int)fp) == FALSE || + useracc((caddr_t)fp, sizeof(struct osigframe), B_WRITE) == FALSE) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ -#ifdef DEBUG - printf("process %d has trashed its stack\n", p->p_pid); -#endif SIGACTION(p, SIGILL) = SIG_DFL; - sig = sigmask(SIGILL); - p->p_sigignore &= ~sig; - p->p_sigcatch &= ~sig; - p->p_sigmask &= ~sig; + SIGDELSET(p->p_sigignore, SIGILL); + SIGDELSET(p->p_sigcatch, SIGILL); + SIGDELSET(p->p_sigmask, SIGILL); psignal(p, SIGILL); return; } - /* - * Build the argument list for the signal handler. - */ + /* Translate the signal if appropriate */ if (p->p_sysent->sv_sigtbl) { - if (sig < p->p_sysent->sv_sigsize) - sig = p->p_sysent->sv_sigtbl[sig]; - else - sig = p->p_sysent->sv_sigsize + 1; + if (sig <= p->p_sysent->sv_sigsize) + sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; } + + /* Build the argument list for the signal handler. */ sf.sf_signum = sig; sf.sf_scp = (register_t)&fp->sf_siginfo.si_sc; - if (p->p_sigacts->ps_siginfo & sigmask(sig)) { - /* - * Signal handler installed with SA_SIGINFO. - */ + if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { + /* Signal handler installed with SA_SIGINFO. */ sf.sf_arg2 = (register_t)&fp->sf_siginfo; sf.sf_siginfo.si_signo = sig; sf.sf_siginfo.si_code = code; - sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; - } else { - /* - * Old FreeBSD-style arguments. - */ + sf.sf_ahu.sf_action = (__osiginfohandler_t *)catcher; + } + else { + /* Old FreeBSD-style arguments. */ sf.sf_arg2 = code; sf.sf_ahu.sf_handler = catcher; } @@ -565,11 +553,9 @@ sendsig(catcher, sig, mask, code) sf.sf_siginfo.si_sc.sc_gs = rgs(); sf.sf_siginfo.si_sc.sc_isp = regs->tf_isp; - /* - * Build the signal context to be used by sigreturn. - */ + /* Build the signal context to be used by sigreturn. */ sf.sf_siginfo.si_sc.sc_onstack = oonstack; - sf.sf_siginfo.si_sc.sc_mask = mask; + SIG2OSIG(*mask, sf.sf_siginfo.si_sc.sc_mask); sf.sf_siginfo.si_sc.sc_sp = regs->tf_esp; sf.sf_siginfo.si_sc.sc_fp = regs->tf_ebp; sf.sf_siginfo.si_sc.sc_pc = regs->tf_eip; @@ -592,8 +578,135 @@ sendsig(catcher, sig, mask, code) sf.sf_siginfo.si_sc.sc_ds = tf->tf_vm86_ds; if (vm86->vm86_has_vme == 0) - sf.sf_siginfo.si_sc.sc_ps = (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) + sf.sf_siginfo.si_sc.sc_ps = + (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) | (vm86->vm86_eflags & (PSL_VIF | PSL_VIP)); + /* see sendsig for comment */ + tf->tf_eflags &= ~(PSL_VM|PSL_NT|PSL_T|PSL_VIF|PSL_VIP); + } + + /* Copy the sigframe out to the user's stack. */ + if (copyout(&sf, fp, sizeof(struct osigframe)) != 0) { + /* + * Something is wrong with the stack pointer. + * ...Kill the process. + */ + sigexit(p, SIGILL); + } + + regs->tf_esp = (int)fp; + regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode); + regs->tf_cs = _ucodesel; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; + regs->tf_fs = _udatasel; + regs->tf_ss = _udatasel; +} + +void +sendsig(catcher, sig, mask, code) + sig_t catcher; + int sig; + sigset_t *mask; + u_long code; +{ + struct proc *p; + struct trapframe *regs; + struct sigacts *psp; + struct sigframe sf, *sfp; + + p = curproc; + + if ((p->p_flag & P_NEWSIGSET) == 0) { + osendsig(catcher, sig, mask, code); + return; + } + + regs = p->p_md.md_regs; + psp = p->p_sigacts; + + /* save user context */ + bzero(&sf, sizeof(struct sigframe)); + sf.sf_uc.uc_sigmask = *mask; + sf.sf_uc.uc_stack = psp->ps_sigstk; + sf.sf_uc.uc_mcontext.mc_tf = *regs; + sf.sf_uc.uc_mcontext.mc_gs = rgs(); + + /* Allocate and validate space for the signal handler context. */ + if ((psp->ps_flags & SAS_ALTSTACK) != 0 && + (psp->ps_sigstk.ss_flags & SS_ONSTACK) == 0 && + SIGISMEMBER(psp->ps_sigonstack, sig)) { + sfp = (struct sigframe *)(psp->ps_sigstk.ss_sp + + psp->ps_sigstk.ss_size - sizeof(struct sigframe)); + psp->ps_sigstk.ss_flags |= SS_ONSTACK; + } + else + sfp = (struct sigframe *)regs->tf_esp - 1; + + /* + * grow() will return FALSE if the sfp will not fit inside the stack + * and the stack can not be grown. useracc will return FALSE if + * access is denied. + */ + if (grow_stack(p, (int)sfp) == FALSE || + useracc((caddr_t)sfp, sizeof(struct sigframe), B_WRITE) == FALSE) { + /* + * Process has trashed its stack; give it an illegal + * instruction to halt it in its tracks. + */ +#ifdef DEBUG + printf("process %d has trashed its stack\n", p->p_pid); +#endif + SIGACTION(p, SIGILL) = SIG_DFL; + SIGDELSET(p->p_sigignore, SIGILL); + SIGDELSET(p->p_sigcatch, SIGILL); + SIGDELSET(p->p_sigmask, SIGILL); + psignal(p, SIGILL); + return; + } + + /* Translate the signal is appropriate */ + if (p->p_sysent->sv_sigtbl) { + if (sig <= p->p_sysent->sv_sigsize) + sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; + } + + /* Build the argument list for the signal handler. */ + sf.sf_signum = sig; + sf.sf_ucontext = (register_t)&sfp->sf_uc; + if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { + /* Signal handler installed with SA_SIGINFO. */ + sf.sf_siginfo = (register_t)&sfp->sf_si; + sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; + + /* fill siginfo structure */ + sf.sf_si.si_signo = sig; + sf.sf_si.si_code = code; + } + else { + /* Old FreeBSD-style arguments. */ + sf.sf_siginfo = code; + sf.sf_ahu.sf_handler = catcher; + } + + /* + * If we're a vm86 process, we want to save the segment registers. + * We also change eflags to be our emulated eflags, not the actual + * eflags. + */ + if (regs->tf_eflags & PSL_VM) { + struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; + struct vm86_kernel *vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; + + sf.sf_uc.uc_mcontext.mc_gs = tf->tf_vm86_gs; + sf.sf_uc.uc_mcontext.mc_tf.tf_fs = tf->tf_vm86_fs; + sf.sf_uc.uc_mcontext.mc_tf.tf_es = tf->tf_vm86_es; + sf.sf_uc.uc_mcontext.mc_tf.tf_ds = tf->tf_vm86_ds; + + if (vm86->vm86_has_vme == 0) + sf.sf_uc.uc_mcontext.mc_tf.tf_eflags = + (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) | + (vm86->vm86_eflags & (PSL_VIF | PSL_VIP)); /* * We should never have PSL_T set when returning from vm86 @@ -606,13 +719,15 @@ sendsig(catcher, sig, mask, code) * does nothing in vm86 mode, but vm86 programs can set it * almost legitimately in probes for old cpu types. */ - tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_T | PSL_VIF | PSL_VIP); + tf->tf_eflags &= ~(PSL_VM|PSL_NT|PSL_T|PSL_VIF|PSL_VIP); } + sf.sf_sigreturn = 0x0ABCDEF0; + /* * Copy the sigframe out to the user's stack. */ - if (copyout(&sf, fp, sizeof(struct sigframe)) != 0) { + if (copyout(&sf, sfp, sizeof(struct sigframe)) != 0) { /* * Something is wrong with the stack pointer. * ...Kill the process. @@ -620,7 +735,7 @@ sendsig(catcher, sig, mask, code) sigexit(p, SIGILL); } - regs->tf_esp = (int)fp; + regs->tf_esp = (int)sfp; regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode); regs->tf_cs = _ucodesel; regs->tf_ds = _udatasel; @@ -638,15 +753,18 @@ sendsig(catcher, sig, mask, code) * make sure that the user has not modified the * state to gain improper privileges. */ +#define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) +#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) + int -sigreturn(p, uap) +osigreturn(p, uap) struct proc *p; - struct sigreturn_args /* { - struct sigcontext *sigcntxp; + struct osigreturn_args /* { + struct osigcontext *sigcntxp; } */ *uap; { - register struct sigcontext *scp; - register struct sigframe *fp; + register struct osigcontext *scp; + register struct osigframe *fp; register struct trapframe *regs = p->p_md.md_regs; int eflags; @@ -657,10 +775,10 @@ sigreturn(p, uap) * for consistency. */ scp = uap->sigcntxp; - fp = (struct sigframe *) - ((caddr_t)scp - offsetof(struct sigframe, sf_siginfo.si_sc)); + fp = (struct osigframe *) + ((caddr_t)scp - offsetof(struct osigframe, sf_siginfo.si_sc)); - if (useracc((caddr_t)fp, sizeof (*fp), B_WRITE) == 0) + if (useracc((caddr_t)fp, sizeof (struct osigframe), B_WRITE) == 0) return(EFAULT); eflags = scp->sc_ps; @@ -700,7 +818,6 @@ sigreturn(p, uap) /* * Don't allow users to change privileged or reserved flags. */ -#define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) /* * XXX do allow users to change the privileged flag PSL_RF. * The cpu sets PSL_RF in tf_eflags for faults. Debuggers @@ -711,10 +828,7 @@ sigreturn(p, uap) * Corruption of the PSL_RF bit at worst causes one more or * one less debugger trap, so allowing it is fairly harmless. */ - if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { -#ifdef DEBUG - printf("sigreturn: eflags = 0x%x\n", eflags); -#endif + if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { return(EINVAL); } @@ -723,11 +837,7 @@ sigreturn(p, uap) * hardware check for invalid selectors, excess privilege in * other selectors, invalid %eip's and invalid %esp's. */ -#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) if (!CS_SECURE(scp->sc_cs)) { -#ifdef DEBUG - printf("sigreturn: cs = 0x%x\n", scp->sc_cs); -#endif trapsignal(p, SIGBUS, T_PROTFLT); return(EINVAL); } @@ -754,7 +864,9 @@ sigreturn(p, uap) p->p_sigacts->ps_sigstk.ss_flags |= SS_ONSTACK; else p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK; - p->p_sigmask = scp->sc_mask & ~sigcantmask; + + OSIG2SIG(scp->sc_mask, p->p_sigmask); + SIG_CANTMASK(p->p_sigmask); regs->tf_ebp = scp->sc_fp; regs->tf_esp = scp->sc_sp; regs->tf_eip = scp->sc_pc; @@ -762,6 +874,99 @@ sigreturn(p, uap) return(EJUSTRETURN); } +int +sigreturn(p, uap) + struct proc *p; + struct sigreturn_args /* { + ucontext_t *sigcntxp; + } */ *uap; +{ + struct trapframe *regs; + ucontext_t *ucp; + struct sigframe *sfp; + int eflags; + + regs = p->p_md.md_regs; + ucp = uap->sigcntxp; + sfp = (struct sigframe *) + ((caddr_t)ucp - offsetof(struct sigframe, sf_uc)); + eflags = ucp->uc_mcontext.mc_tf.tf_eflags; + + if (useracc((caddr_t)sfp, sizeof(struct sigframe), B_WRITE) == 0) + return(EFAULT); + + if (eflags & PSL_VM) { + struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; + struct vm86_kernel *vm86; + + /* + * if pcb_ext == 0 or vm86_inited == 0, the user hasn't + * set up the vm86 area, and we can't enter vm86 mode. + */ + if (p->p_addr->u_pcb.pcb_ext == 0) + return (EINVAL); + vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; + if (vm86->vm86_inited == 0) + return (EINVAL); + + /* go back to user mode if both flags are set */ + if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) + trapsignal(p, SIGBUS, 0); + + if (vm86->vm86_has_vme) { + eflags = (tf->tf_eflags & ~VME_USERCHANGE) | + (eflags & VME_USERCHANGE) | PSL_VM; + } else { + vm86->vm86_eflags = eflags; /* save VIF, VIP */ + eflags = (tf->tf_eflags & ~VM_USERCHANGE) | (eflags & VM_USERCHANGE) | PSL_VM; + } + *regs = ucp->uc_mcontext.mc_tf; + tf->tf_vm86_ds = tf->tf_ds; + tf->tf_vm86_es = tf->tf_es; + tf->tf_vm86_fs = tf->tf_fs; + tf->tf_vm86_gs = ucp->uc_mcontext.mc_gs; + tf->tf_ds = _udatasel; + tf->tf_es = _udatasel; + tf->tf_fs = _udatasel; + } else { + /* + * Don't allow users to change privileged or reserved flags. + */ + /* + * XXX do allow users to change the privileged flag PSL_RF. + * The cpu sets PSL_RF in tf_eflags for faults. Debuggers + * should sometimes set it there too. tf_eflags is kept in + * the signal context during signal handling and there is no + * other place to remember it, so the PSL_RF bit may be + * corrupted by the signal handler without us knowing. + * Corruption of the PSL_RF bit at worst causes one more or + * one less debugger trap, so allowing it is fairly harmless. + */ + if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { + printf("sigreturn: eflags = 0x%x\n", eflags); + return(EINVAL); + } + + *regs = ucp->uc_mcontext.mc_tf; + + /* + * Don't allow users to load a valid privileged %cs. Let the + * hardware check for invalid selectors, excess privilege in + * other selectors, invalid %eip's and invalid %esp's. + */ + if (!CS_SECURE(regs->tf_cs)) { + printf("sigreturn: cs = 0x%x\n", regs->tf_cs); + trapsignal(p, SIGBUS, T_PROTFLT); + return(EINVAL); + } + } + + p->p_sigacts->ps_sigstk = ucp->uc_stack; + p->p_sigmask = ucp->uc_sigmask; + SIG_CANTMASK(p->p_sigmask); + return(EJUSTRETURN); +} + /* * Machine dependent boot() routine * @@ -1862,7 +2067,7 @@ int ptrace_write_u(p, off, data) tp = p->p_md.md_regs; frame_copy = *tp; *(int *)((char *)&frame_copy + (off - min)) = data; - if (!EFLAGS_SECURE(frame_copy.tf_eflags, tp->tf_eflags) || + if (!EFL_SECURE(frame_copy.tf_eflags, tp->tf_eflags) || !CS_SECURE(frame_copy.tf_cs)) return (EINVAL); *(int*)((char *)p->p_addr + off) = data; @@ -1914,7 +2119,7 @@ set_regs(p, regs) struct trapframe *tp; tp = p->p_md.md_regs; - if (!EFLAGS_SECURE(regs->r_eflags, tp->tf_eflags) || + if (!EFL_SECURE(regs->r_eflags, tp->tf_eflags) || !CS_SECURE(regs->r_cs)) return (EINVAL); tp->tf_fs = regs->r_fs; diff --git a/sys/amd64/include/db_machdep.h b/sys/amd64/include/db_machdep.h index d5022d8..719c556 100644 --- a/sys/amd64/include/db_machdep.h +++ b/sys/amd64/include/db_machdep.h @@ -30,6 +30,7 @@ #define _MACHINE_DB_MACHDEP_H_ #include <machine/frame.h> +#include <machine/trap.h> #include <machine/psl.h> #define i386_saved_state trapframe diff --git a/sys/amd64/include/frame.h b/sys/amd64/include/frame.h index b212d6c..634e690 100644 --- a/sys/amd64/include/frame.h +++ b/sys/amd64/include/frame.h @@ -40,8 +40,6 @@ #ifndef _MACHINE_FRAME_H_ #define _MACHINE_FRAME_H_ 1 -#include <sys/signal.h> - /* * System stack frames. */ @@ -157,42 +155,6 @@ struct clockframe { int cf_ss; }; -/* - * Signal frame, arguments passed to application signal handlers. - */ -struct sigframe { - /* - * The first three members may be used by applications. - */ - - register_t sf_signum; - - /* - * Either 'int' for old-style FreeBSD handler or 'siginfo_t *' - * pointing to sf_siginfo for SA_SIGINFO handlers. - */ - register_t sf_arg2; - - /* Points to sf_siginfo.si_sc. */ - register_t sf_scp; - - /* - * The following arguments are not constrained by the - * function call protocol. - * Applications are not supposed to access these members, - * except using the pointers we provide in the first three - * arguments. - */ - char *sf_addr; - union { - __siginfohandler_t *sf_action; - __sighandler_t *sf_handler; - } sf_ahu; - - /* In the SA_SIGINFO case, sf_arg2 points here. */ - siginfo_t sf_siginfo; -}; - int kdb_trap __P((int, int, struct trapframe *)); extern int (*pmath_emulate) __P((struct trapframe *)); diff --git a/sys/amd64/include/setjmp.h b/sys/amd64/include/setjmp.h index 173ea2d..3097df7 100644 --- a/sys/amd64/include/setjmp.h +++ b/sys/amd64/include/setjmp.h @@ -32,7 +32,7 @@ * */ -#define _JBLEN 8 /* Size of the jmp_buf on x86. */ +#define _JBLEN 11 /* Size of the jmp_buf on x86. */ /* * jmp_buf and sigjmp_buf are encapsulated in different structs to force diff --git a/sys/amd64/include/sigframe.h b/sys/amd64/include/sigframe.h new file mode 100644 index 0000000..9c47915 --- /dev/null +++ b/sys/amd64/include/sigframe.h @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 1999 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_SIGFRAME_H_ +#define _MACHINE_SIGFRAME_H_ 1 + +struct osigframe { + /* + * The first three members may be used by applications. + */ + + register_t sf_signum; + + /* + * Either 'int' for old-style FreeBSD handler or 'siginfo_t *' + * pointing to sf_siginfo for SA_SIGINFO handlers. + */ + register_t sf_arg2; + + /* Points to sf_siginfo.si_sc. */ + register_t sf_scp; + + /* + * The following arguments are not constrained by the + * function call protocol. + * Applications are not supposed to access these members, + * except using the pointers we provide in the first three + * arguments. + */ + + char *sf_addr; + + union { + __osiginfohandler_t *sf_action; + __sighandler_t *sf_handler; + } sf_ahu; + + /* In the SA_SIGINFO case, sf_arg2 points here. */ + osiginfo_t sf_siginfo; +}; + +struct sigframe { + /* + * The first three members may be used by applications. + */ + register_t sf_signum; + register_t sf_siginfo; /* code or pointer to sf_si */ + register_t sf_ucontext; /* points to sf_uc */ + register_t __spare__; /* Align sf_ahu */ + union { + __siginfohandler_t *sf_action; + __sighandler_t *sf_handler; + } sf_ahu; + register_t sf_sigreturn; /* sigreturn to use */ + siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case) */ + ucontext_t sf_uc; /* = *sf_ucontext */ +}; + +#endif /* _MACHINE_SIGFRAME_H_ */ diff --git a/sys/amd64/include/signal.h b/sys/amd64/include/signal.h index deaa06c..e9f739e 100644 --- a/sys/amd64/include/signal.h +++ b/sys/amd64/include/signal.h @@ -54,33 +54,35 @@ typedef int sig_atomic_t; * to the handler to allow it to restore state properly if * a non-standard exit is performed. */ -struct sigcontext { - int sc_onstack; /* sigstack state to restore */ - int sc_mask; /* signal mask to restore */ - int sc_esp; /* machine state */ - int sc_ebp; - int sc_isp; - int sc_eip; - int sc_efl; - int sc_es; - int sc_ds; - int sc_cs; - int sc_ss; - int sc_edi; - int sc_esi; - int sc_ebx; - int sc_edx; - int sc_ecx; - int sc_eax; - int sc_gs; - int sc_fs; -# define sc_sp sc_esp -# define sc_fp sc_ebp -# define sc_pc sc_eip -# define sc_ps sc_efl -# define sc_eflags sc_efl - int sc_trapno; - int sc_err; +typedef unsigned int osigset_t; + +struct osigcontext { + int sc_onstack; /* sigstack state to restore */ + osigset_t sc_mask; /* signal mask to restore */ + int sc_esp; /* machine state */ + int sc_ebp; + int sc_isp; + int sc_eip; + int sc_efl; + int sc_es; + int sc_ds; + int sc_cs; + int sc_ss; + int sc_edi; + int sc_esi; + int sc_ebx; + int sc_edx; + int sc_ecx; + int sc_eax; + int sc_gs; + int sc_fs; +#define sc_sp sc_esp +#define sc_fp sc_ebp +#define sc_pc sc_eip +#define sc_ps sc_efl +#define sc_eflags sc_efl + int sc_trapno; + int sc_err; }; #endif /* !_ANSI_SOURCE && !_POSIX_SOURCE */ diff --git a/sys/amd64/include/ucontext.h b/sys/amd64/include/ucontext.h new file mode 100644 index 0000000..bdf2e1d --- /dev/null +++ b/sys/amd64/include/ucontext.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 1999 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_UCONTEXT_H_ +#define _MACHINE_UCONTEXT_H_ 1 + +#include <machine/frame.h> + +typedef struct { + int mc_gs; /* %gs */ + struct trapframe mc_tf; /* trapframe */ + int mc_fpregs[28]; /* env87 + fpacc87 + u_long */ + int __spare__[17]; +} mcontext_t; + +#endif /* _MACHINE_UCONTEXT_H_ */ diff --git a/sys/i386/i386/genassym.c b/sys/i386/i386/genassym.c index d4023cc..62dbf53 100644 --- a/sys/i386/i386/genassym.c +++ b/sys/i386/i386/genassym.c @@ -72,6 +72,8 @@ #include <machine/globaldata.h> #include <machine/vm86.h> +#include <machine/sigframe.h> + #define OS(s, m) ((u_int)offsetof(struct s, m)) int main __P((void)); @@ -147,10 +149,16 @@ main() printf("#define\tTF_EFLAGS %#x\n", OS(trapframe, tf_eflags)); printf("#define\tSIGF_HANDLER %#x\n", OS(sigframe, sf_ahu.sf_handler)); - printf("#define\tSIGF_SC %#x\n", OS(sigframe, sf_siginfo.si_sc)); - printf("#define\tSC_PS %#x\n", OS(sigcontext, sc_ps)); - printf("#define\tSC_FS %#x\n", OS(sigcontext, sc_fs)); - printf("#define\tSC_GS %#x\n", OS(sigcontext, sc_gs)); + printf("#define\tSIGF_SIGRET %#x\n", OS(sigframe, sf_sigreturn)); + printf("#define\tSIGF_SC %#x\n", OS(osigframe, sf_siginfo.si_sc)); + printf("#define\tSIGF_UC %#x\n", OS(sigframe, sf_uc)); + + printf("#define\tSC_PS %#x\n", OS(osigcontext, sc_ps)); + printf("#define\tSC_FS %#x\n", OS(osigcontext, sc_fs)); + printf("#define\tSC_GS %#x\n", OS(osigcontext, sc_gs)); + + printf("#define\tUC_EFLAGS %#x\n", OS(__ucontext, uc_mcontext.mc_tf.tf_eflags)); + printf("#define\tUC_GS %#x\n", OS(__ucontext, uc_mcontext.mc_gs)); printf("#define\tB_READ %#x\n", B_READ); printf("#define\tENOENT %d\n", ENOENT); diff --git a/sys/i386/i386/locore.s b/sys/i386/i386/locore.s index ad499bd..e87c275 100644 --- a/sys/i386/i386/locore.s +++ b/sys/i386/i386/locore.s @@ -414,18 +414,38 @@ NON_GPROF_ENTRY(prepare_usermode) * Signal trampoline, copied to top of user stack */ NON_GPROF_ENTRY(sigcode) - call SIGF_HANDLER(%esp) - lea SIGF_SC(%esp),%eax /* scp (the call may have clobbered the */ - /* copy at 8(%esp)) */ + call SIGF_HANDLER(%esp) /* call signal handler */ + movl SIGF_SIGRET(%esp),%eax /* Get sigreturn cookie */ + cmpl $0x0ABCDEF0,%eax /* New one? */ + jne 3f +/* New signalling code */ + lea SIGF_UC(%esp),%eax /* get ucontext */ pushl %eax - pushl %eax /* junk to fake return address */ - testl $PSL_VM,SC_PS(%eax) + testl $PSL_VM,UC_EFLAGS(%eax) jne 1f - movl SC_GS(%eax),%gs /* restore %gs */ + movl UC_GS(%eax),%gs /* restore %gs */ 1: - movl $SYS_sigreturn,%eax /* sigreturn() */ - int $0x80 /* enter kernel with args on stack */ -2: jmp 2b + movl $SYS_sigreturn,%eax + pushl %eax /* junk to fake return addr. */ + int $0x80 /* enter kernel with args */ + /* on stack */ +2: + jmp 2b +/* Old signalling code */ +3: + lea SIGF_SC(%esp),%eax /* get sigcontext */ + pushl %eax + testl $PSL_VM,SC_PS(%eax) + jne 4f + movl SC_GS(%eax),%gs /* restore %gs */ +4: + movl $SYS_osigreturn,%eax + pushl %eax /* junk to fake return addr. */ + int $0x80 /* enter kernel with args */ + /* on stack */ +5: + jmp 5b + ALIGN_TEXT _esigcode: diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index 7b712d2..b5280c6 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -127,6 +127,7 @@ #include <machine/vm86.h> #include <machine/random.h> #include <sys/ptrace.h> +#include <machine/sigframe.h> extern void init386 __P((int first)); extern void dblfault_handler __P((void)); @@ -471,79 +472,66 @@ netisr_sysinit(data) * frame pointer, it returns to the user * specified pc, psl. */ -void -sendsig(catcher, sig, mask, code) - sig_t catcher; - int sig, mask; - u_long code; +static void +osendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) { register struct proc *p = curproc; register struct trapframe *regs; - register struct sigframe *fp; - struct sigframe sf; + register struct osigframe *fp; + struct osigframe sf; struct sigacts *psp = p->p_sigacts; int oonstack; regs = p->p_md.md_regs; - oonstack = psp->ps_sigstk.ss_flags & SS_ONSTACK; - /* - * Allocate and validate space for the signal handler context. - */ - if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack && - (psp->ps_sigonstack & sigmask(sig))) { - fp = (struct sigframe *)(psp->ps_sigstk.ss_sp + - psp->ps_sigstk.ss_size - sizeof(struct sigframe)); + oonstack = (psp->ps_sigstk.ss_flags & SS_ONSTACK) ? 1 : 0; + + /* Allocate and validate space for the signal handler context. */ + if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack && + SIGISMEMBER(psp->ps_sigonstack, sig)) { + fp = (struct osigframe *)(psp->ps_sigstk.ss_sp + + psp->ps_sigstk.ss_size - sizeof(struct osigframe)); psp->ps_sigstk.ss_flags |= SS_ONSTACK; - } else { - fp = (struct sigframe *)regs->tf_esp - 1; } + else + fp = (struct osigframe *)regs->tf_esp - 1; /* * grow() will return FALSE if the fp will not fit inside the stack * and the stack can not be grown. useracc will return FALSE * if access is denied. */ - if ((grow_stack (p, (int)fp) == FALSE) || - (useracc((caddr_t)fp, sizeof(struct sigframe), B_WRITE) == FALSE)) { + if (grow_stack(p, (int)fp) == FALSE || + useracc((caddr_t)fp, sizeof(struct osigframe), B_WRITE) == FALSE) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ -#ifdef DEBUG - printf("process %d has trashed its stack\n", p->p_pid); -#endif SIGACTION(p, SIGILL) = SIG_DFL; - sig = sigmask(SIGILL); - p->p_sigignore &= ~sig; - p->p_sigcatch &= ~sig; - p->p_sigmask &= ~sig; + SIGDELSET(p->p_sigignore, SIGILL); + SIGDELSET(p->p_sigcatch, SIGILL); + SIGDELSET(p->p_sigmask, SIGILL); psignal(p, SIGILL); return; } - /* - * Build the argument list for the signal handler. - */ + /* Translate the signal if appropriate */ if (p->p_sysent->sv_sigtbl) { - if (sig < p->p_sysent->sv_sigsize) - sig = p->p_sysent->sv_sigtbl[sig]; - else - sig = p->p_sysent->sv_sigsize + 1; + if (sig <= p->p_sysent->sv_sigsize) + sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; } + + /* Build the argument list for the signal handler. */ sf.sf_signum = sig; sf.sf_scp = (register_t)&fp->sf_siginfo.si_sc; - if (p->p_sigacts->ps_siginfo & sigmask(sig)) { - /* - * Signal handler installed with SA_SIGINFO. - */ + if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { + /* Signal handler installed with SA_SIGINFO. */ sf.sf_arg2 = (register_t)&fp->sf_siginfo; sf.sf_siginfo.si_signo = sig; sf.sf_siginfo.si_code = code; - sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; - } else { - /* - * Old FreeBSD-style arguments. - */ + sf.sf_ahu.sf_action = (__osiginfohandler_t *)catcher; + } + else { + /* Old FreeBSD-style arguments. */ sf.sf_arg2 = code; sf.sf_ahu.sf_handler = catcher; } @@ -565,11 +553,9 @@ sendsig(catcher, sig, mask, code) sf.sf_siginfo.si_sc.sc_gs = rgs(); sf.sf_siginfo.si_sc.sc_isp = regs->tf_isp; - /* - * Build the signal context to be used by sigreturn. - */ + /* Build the signal context to be used by sigreturn. */ sf.sf_siginfo.si_sc.sc_onstack = oonstack; - sf.sf_siginfo.si_sc.sc_mask = mask; + SIG2OSIG(*mask, sf.sf_siginfo.si_sc.sc_mask); sf.sf_siginfo.si_sc.sc_sp = regs->tf_esp; sf.sf_siginfo.si_sc.sc_fp = regs->tf_ebp; sf.sf_siginfo.si_sc.sc_pc = regs->tf_eip; @@ -592,8 +578,135 @@ sendsig(catcher, sig, mask, code) sf.sf_siginfo.si_sc.sc_ds = tf->tf_vm86_ds; if (vm86->vm86_has_vme == 0) - sf.sf_siginfo.si_sc.sc_ps = (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) + sf.sf_siginfo.si_sc.sc_ps = + (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) | (vm86->vm86_eflags & (PSL_VIF | PSL_VIP)); + /* see sendsig for comment */ + tf->tf_eflags &= ~(PSL_VM|PSL_NT|PSL_T|PSL_VIF|PSL_VIP); + } + + /* Copy the sigframe out to the user's stack. */ + if (copyout(&sf, fp, sizeof(struct osigframe)) != 0) { + /* + * Something is wrong with the stack pointer. + * ...Kill the process. + */ + sigexit(p, SIGILL); + } + + regs->tf_esp = (int)fp; + regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode); + regs->tf_cs = _ucodesel; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; + regs->tf_fs = _udatasel; + regs->tf_ss = _udatasel; +} + +void +sendsig(catcher, sig, mask, code) + sig_t catcher; + int sig; + sigset_t *mask; + u_long code; +{ + struct proc *p; + struct trapframe *regs; + struct sigacts *psp; + struct sigframe sf, *sfp; + + p = curproc; + + if ((p->p_flag & P_NEWSIGSET) == 0) { + osendsig(catcher, sig, mask, code); + return; + } + + regs = p->p_md.md_regs; + psp = p->p_sigacts; + + /* save user context */ + bzero(&sf, sizeof(struct sigframe)); + sf.sf_uc.uc_sigmask = *mask; + sf.sf_uc.uc_stack = psp->ps_sigstk; + sf.sf_uc.uc_mcontext.mc_tf = *regs; + sf.sf_uc.uc_mcontext.mc_gs = rgs(); + + /* Allocate and validate space for the signal handler context. */ + if ((psp->ps_flags & SAS_ALTSTACK) != 0 && + (psp->ps_sigstk.ss_flags & SS_ONSTACK) == 0 && + SIGISMEMBER(psp->ps_sigonstack, sig)) { + sfp = (struct sigframe *)(psp->ps_sigstk.ss_sp + + psp->ps_sigstk.ss_size - sizeof(struct sigframe)); + psp->ps_sigstk.ss_flags |= SS_ONSTACK; + } + else + sfp = (struct sigframe *)regs->tf_esp - 1; + + /* + * grow() will return FALSE if the sfp will not fit inside the stack + * and the stack can not be grown. useracc will return FALSE if + * access is denied. + */ + if (grow_stack(p, (int)sfp) == FALSE || + useracc((caddr_t)sfp, sizeof(struct sigframe), B_WRITE) == FALSE) { + /* + * Process has trashed its stack; give it an illegal + * instruction to halt it in its tracks. + */ +#ifdef DEBUG + printf("process %d has trashed its stack\n", p->p_pid); +#endif + SIGACTION(p, SIGILL) = SIG_DFL; + SIGDELSET(p->p_sigignore, SIGILL); + SIGDELSET(p->p_sigcatch, SIGILL); + SIGDELSET(p->p_sigmask, SIGILL); + psignal(p, SIGILL); + return; + } + + /* Translate the signal is appropriate */ + if (p->p_sysent->sv_sigtbl) { + if (sig <= p->p_sysent->sv_sigsize) + sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; + } + + /* Build the argument list for the signal handler. */ + sf.sf_signum = sig; + sf.sf_ucontext = (register_t)&sfp->sf_uc; + if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { + /* Signal handler installed with SA_SIGINFO. */ + sf.sf_siginfo = (register_t)&sfp->sf_si; + sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; + + /* fill siginfo structure */ + sf.sf_si.si_signo = sig; + sf.sf_si.si_code = code; + } + else { + /* Old FreeBSD-style arguments. */ + sf.sf_siginfo = code; + sf.sf_ahu.sf_handler = catcher; + } + + /* + * If we're a vm86 process, we want to save the segment registers. + * We also change eflags to be our emulated eflags, not the actual + * eflags. + */ + if (regs->tf_eflags & PSL_VM) { + struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; + struct vm86_kernel *vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; + + sf.sf_uc.uc_mcontext.mc_gs = tf->tf_vm86_gs; + sf.sf_uc.uc_mcontext.mc_tf.tf_fs = tf->tf_vm86_fs; + sf.sf_uc.uc_mcontext.mc_tf.tf_es = tf->tf_vm86_es; + sf.sf_uc.uc_mcontext.mc_tf.tf_ds = tf->tf_vm86_ds; + + if (vm86->vm86_has_vme == 0) + sf.sf_uc.uc_mcontext.mc_tf.tf_eflags = + (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) | + (vm86->vm86_eflags & (PSL_VIF | PSL_VIP)); /* * We should never have PSL_T set when returning from vm86 @@ -606,13 +719,15 @@ sendsig(catcher, sig, mask, code) * does nothing in vm86 mode, but vm86 programs can set it * almost legitimately in probes for old cpu types. */ - tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_T | PSL_VIF | PSL_VIP); + tf->tf_eflags &= ~(PSL_VM|PSL_NT|PSL_T|PSL_VIF|PSL_VIP); } + sf.sf_sigreturn = 0x0ABCDEF0; + /* * Copy the sigframe out to the user's stack. */ - if (copyout(&sf, fp, sizeof(struct sigframe)) != 0) { + if (copyout(&sf, sfp, sizeof(struct sigframe)) != 0) { /* * Something is wrong with the stack pointer. * ...Kill the process. @@ -620,7 +735,7 @@ sendsig(catcher, sig, mask, code) sigexit(p, SIGILL); } - regs->tf_esp = (int)fp; + regs->tf_esp = (int)sfp; regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode); regs->tf_cs = _ucodesel; regs->tf_ds = _udatasel; @@ -638,15 +753,18 @@ sendsig(catcher, sig, mask, code) * make sure that the user has not modified the * state to gain improper privileges. */ +#define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) +#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) + int -sigreturn(p, uap) +osigreturn(p, uap) struct proc *p; - struct sigreturn_args /* { - struct sigcontext *sigcntxp; + struct osigreturn_args /* { + struct osigcontext *sigcntxp; } */ *uap; { - register struct sigcontext *scp; - register struct sigframe *fp; + register struct osigcontext *scp; + register struct osigframe *fp; register struct trapframe *regs = p->p_md.md_regs; int eflags; @@ -657,10 +775,10 @@ sigreturn(p, uap) * for consistency. */ scp = uap->sigcntxp; - fp = (struct sigframe *) - ((caddr_t)scp - offsetof(struct sigframe, sf_siginfo.si_sc)); + fp = (struct osigframe *) + ((caddr_t)scp - offsetof(struct osigframe, sf_siginfo.si_sc)); - if (useracc((caddr_t)fp, sizeof (*fp), B_WRITE) == 0) + if (useracc((caddr_t)fp, sizeof (struct osigframe), B_WRITE) == 0) return(EFAULT); eflags = scp->sc_ps; @@ -700,7 +818,6 @@ sigreturn(p, uap) /* * Don't allow users to change privileged or reserved flags. */ -#define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) /* * XXX do allow users to change the privileged flag PSL_RF. * The cpu sets PSL_RF in tf_eflags for faults. Debuggers @@ -711,10 +828,7 @@ sigreturn(p, uap) * Corruption of the PSL_RF bit at worst causes one more or * one less debugger trap, so allowing it is fairly harmless. */ - if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { -#ifdef DEBUG - printf("sigreturn: eflags = 0x%x\n", eflags); -#endif + if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { return(EINVAL); } @@ -723,11 +837,7 @@ sigreturn(p, uap) * hardware check for invalid selectors, excess privilege in * other selectors, invalid %eip's and invalid %esp's. */ -#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) if (!CS_SECURE(scp->sc_cs)) { -#ifdef DEBUG - printf("sigreturn: cs = 0x%x\n", scp->sc_cs); -#endif trapsignal(p, SIGBUS, T_PROTFLT); return(EINVAL); } @@ -754,7 +864,9 @@ sigreturn(p, uap) p->p_sigacts->ps_sigstk.ss_flags |= SS_ONSTACK; else p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK; - p->p_sigmask = scp->sc_mask & ~sigcantmask; + + OSIG2SIG(scp->sc_mask, p->p_sigmask); + SIG_CANTMASK(p->p_sigmask); regs->tf_ebp = scp->sc_fp; regs->tf_esp = scp->sc_sp; regs->tf_eip = scp->sc_pc; @@ -762,6 +874,99 @@ sigreturn(p, uap) return(EJUSTRETURN); } +int +sigreturn(p, uap) + struct proc *p; + struct sigreturn_args /* { + ucontext_t *sigcntxp; + } */ *uap; +{ + struct trapframe *regs; + ucontext_t *ucp; + struct sigframe *sfp; + int eflags; + + regs = p->p_md.md_regs; + ucp = uap->sigcntxp; + sfp = (struct sigframe *) + ((caddr_t)ucp - offsetof(struct sigframe, sf_uc)); + eflags = ucp->uc_mcontext.mc_tf.tf_eflags; + + if (useracc((caddr_t)sfp, sizeof(struct sigframe), B_WRITE) == 0) + return(EFAULT); + + if (eflags & PSL_VM) { + struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; + struct vm86_kernel *vm86; + + /* + * if pcb_ext == 0 or vm86_inited == 0, the user hasn't + * set up the vm86 area, and we can't enter vm86 mode. + */ + if (p->p_addr->u_pcb.pcb_ext == 0) + return (EINVAL); + vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; + if (vm86->vm86_inited == 0) + return (EINVAL); + + /* go back to user mode if both flags are set */ + if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) + trapsignal(p, SIGBUS, 0); + + if (vm86->vm86_has_vme) { + eflags = (tf->tf_eflags & ~VME_USERCHANGE) | + (eflags & VME_USERCHANGE) | PSL_VM; + } else { + vm86->vm86_eflags = eflags; /* save VIF, VIP */ + eflags = (tf->tf_eflags & ~VM_USERCHANGE) | (eflags & VM_USERCHANGE) | PSL_VM; + } + *regs = ucp->uc_mcontext.mc_tf; + tf->tf_vm86_ds = tf->tf_ds; + tf->tf_vm86_es = tf->tf_es; + tf->tf_vm86_fs = tf->tf_fs; + tf->tf_vm86_gs = ucp->uc_mcontext.mc_gs; + tf->tf_ds = _udatasel; + tf->tf_es = _udatasel; + tf->tf_fs = _udatasel; + } else { + /* + * Don't allow users to change privileged or reserved flags. + */ + /* + * XXX do allow users to change the privileged flag PSL_RF. + * The cpu sets PSL_RF in tf_eflags for faults. Debuggers + * should sometimes set it there too. tf_eflags is kept in + * the signal context during signal handling and there is no + * other place to remember it, so the PSL_RF bit may be + * corrupted by the signal handler without us knowing. + * Corruption of the PSL_RF bit at worst causes one more or + * one less debugger trap, so allowing it is fairly harmless. + */ + if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { + printf("sigreturn: eflags = 0x%x\n", eflags); + return(EINVAL); + } + + *regs = ucp->uc_mcontext.mc_tf; + + /* + * Don't allow users to load a valid privileged %cs. Let the + * hardware check for invalid selectors, excess privilege in + * other selectors, invalid %eip's and invalid %esp's. + */ + if (!CS_SECURE(regs->tf_cs)) { + printf("sigreturn: cs = 0x%x\n", regs->tf_cs); + trapsignal(p, SIGBUS, T_PROTFLT); + return(EINVAL); + } + } + + p->p_sigacts->ps_sigstk = ucp->uc_stack; + p->p_sigmask = ucp->uc_sigmask; + SIG_CANTMASK(p->p_sigmask); + return(EJUSTRETURN); +} + /* * Machine dependent boot() routine * @@ -1862,7 +2067,7 @@ int ptrace_write_u(p, off, data) tp = p->p_md.md_regs; frame_copy = *tp; *(int *)((char *)&frame_copy + (off - min)) = data; - if (!EFLAGS_SECURE(frame_copy.tf_eflags, tp->tf_eflags) || + if (!EFL_SECURE(frame_copy.tf_eflags, tp->tf_eflags) || !CS_SECURE(frame_copy.tf_cs)) return (EINVAL); *(int*)((char *)p->p_addr + off) = data; @@ -1914,7 +2119,7 @@ set_regs(p, regs) struct trapframe *tp; tp = p->p_md.md_regs; - if (!EFLAGS_SECURE(regs->r_eflags, tp->tf_eflags) || + if (!EFL_SECURE(regs->r_eflags, tp->tf_eflags) || !CS_SECURE(regs->r_cs)) return (EINVAL); tp->tf_fs = regs->r_fs; diff --git a/sys/i386/include/db_machdep.h b/sys/i386/include/db_machdep.h index d5022d8..719c556 100644 --- a/sys/i386/include/db_machdep.h +++ b/sys/i386/include/db_machdep.h @@ -30,6 +30,7 @@ #define _MACHINE_DB_MACHDEP_H_ #include <machine/frame.h> +#include <machine/trap.h> #include <machine/psl.h> #define i386_saved_state trapframe diff --git a/sys/i386/include/frame.h b/sys/i386/include/frame.h index b212d6c..634e690 100644 --- a/sys/i386/include/frame.h +++ b/sys/i386/include/frame.h @@ -40,8 +40,6 @@ #ifndef _MACHINE_FRAME_H_ #define _MACHINE_FRAME_H_ 1 -#include <sys/signal.h> - /* * System stack frames. */ @@ -157,42 +155,6 @@ struct clockframe { int cf_ss; }; -/* - * Signal frame, arguments passed to application signal handlers. - */ -struct sigframe { - /* - * The first three members may be used by applications. - */ - - register_t sf_signum; - - /* - * Either 'int' for old-style FreeBSD handler or 'siginfo_t *' - * pointing to sf_siginfo for SA_SIGINFO handlers. - */ - register_t sf_arg2; - - /* Points to sf_siginfo.si_sc. */ - register_t sf_scp; - - /* - * The following arguments are not constrained by the - * function call protocol. - * Applications are not supposed to access these members, - * except using the pointers we provide in the first three - * arguments. - */ - char *sf_addr; - union { - __siginfohandler_t *sf_action; - __sighandler_t *sf_handler; - } sf_ahu; - - /* In the SA_SIGINFO case, sf_arg2 points here. */ - siginfo_t sf_siginfo; -}; - int kdb_trap __P((int, int, struct trapframe *)); extern int (*pmath_emulate) __P((struct trapframe *)); diff --git a/sys/i386/include/setjmp.h b/sys/i386/include/setjmp.h index 173ea2d..3097df7 100644 --- a/sys/i386/include/setjmp.h +++ b/sys/i386/include/setjmp.h @@ -32,7 +32,7 @@ * */ -#define _JBLEN 8 /* Size of the jmp_buf on x86. */ +#define _JBLEN 11 /* Size of the jmp_buf on x86. */ /* * jmp_buf and sigjmp_buf are encapsulated in different structs to force diff --git a/sys/i386/include/sigframe.h b/sys/i386/include/sigframe.h new file mode 100644 index 0000000..9c47915 --- /dev/null +++ b/sys/i386/include/sigframe.h @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 1999 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_SIGFRAME_H_ +#define _MACHINE_SIGFRAME_H_ 1 + +struct osigframe { + /* + * The first three members may be used by applications. + */ + + register_t sf_signum; + + /* + * Either 'int' for old-style FreeBSD handler or 'siginfo_t *' + * pointing to sf_siginfo for SA_SIGINFO handlers. + */ + register_t sf_arg2; + + /* Points to sf_siginfo.si_sc. */ + register_t sf_scp; + + /* + * The following arguments are not constrained by the + * function call protocol. + * Applications are not supposed to access these members, + * except using the pointers we provide in the first three + * arguments. + */ + + char *sf_addr; + + union { + __osiginfohandler_t *sf_action; + __sighandler_t *sf_handler; + } sf_ahu; + + /* In the SA_SIGINFO case, sf_arg2 points here. */ + osiginfo_t sf_siginfo; +}; + +struct sigframe { + /* + * The first three members may be used by applications. + */ + register_t sf_signum; + register_t sf_siginfo; /* code or pointer to sf_si */ + register_t sf_ucontext; /* points to sf_uc */ + register_t __spare__; /* Align sf_ahu */ + union { + __siginfohandler_t *sf_action; + __sighandler_t *sf_handler; + } sf_ahu; + register_t sf_sigreturn; /* sigreturn to use */ + siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case) */ + ucontext_t sf_uc; /* = *sf_ucontext */ +}; + +#endif /* _MACHINE_SIGFRAME_H_ */ diff --git a/sys/i386/include/signal.h b/sys/i386/include/signal.h index deaa06c..e9f739e 100644 --- a/sys/i386/include/signal.h +++ b/sys/i386/include/signal.h @@ -54,33 +54,35 @@ typedef int sig_atomic_t; * to the handler to allow it to restore state properly if * a non-standard exit is performed. */ -struct sigcontext { - int sc_onstack; /* sigstack state to restore */ - int sc_mask; /* signal mask to restore */ - int sc_esp; /* machine state */ - int sc_ebp; - int sc_isp; - int sc_eip; - int sc_efl; - int sc_es; - int sc_ds; - int sc_cs; - int sc_ss; - int sc_edi; - int sc_esi; - int sc_ebx; - int sc_edx; - int sc_ecx; - int sc_eax; - int sc_gs; - int sc_fs; -# define sc_sp sc_esp -# define sc_fp sc_ebp -# define sc_pc sc_eip -# define sc_ps sc_efl -# define sc_eflags sc_efl - int sc_trapno; - int sc_err; +typedef unsigned int osigset_t; + +struct osigcontext { + int sc_onstack; /* sigstack state to restore */ + osigset_t sc_mask; /* signal mask to restore */ + int sc_esp; /* machine state */ + int sc_ebp; + int sc_isp; + int sc_eip; + int sc_efl; + int sc_es; + int sc_ds; + int sc_cs; + int sc_ss; + int sc_edi; + int sc_esi; + int sc_ebx; + int sc_edx; + int sc_ecx; + int sc_eax; + int sc_gs; + int sc_fs; +#define sc_sp sc_esp +#define sc_fp sc_ebp +#define sc_pc sc_eip +#define sc_ps sc_efl +#define sc_eflags sc_efl + int sc_trapno; + int sc_err; }; #endif /* !_ANSI_SOURCE && !_POSIX_SOURCE */ diff --git a/sys/i386/include/ucontext.h b/sys/i386/include/ucontext.h new file mode 100644 index 0000000..bdf2e1d --- /dev/null +++ b/sys/i386/include/ucontext.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 1999 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_UCONTEXT_H_ +#define _MACHINE_UCONTEXT_H_ 1 + +#include <machine/frame.h> + +typedef struct { + int mc_gs; /* %gs */ + struct trapframe mc_tf; /* trapframe */ + int mc_fpregs[28]; /* env87 + fpacc87 + u_long */ + int __spare__[17]; +} mcontext_t; + +#endif /* _MACHINE_UCONTEXT_H_ */ diff --git a/sys/pc98/i386/machdep.c b/sys/pc98/i386/machdep.c index 93580f9..2bc0d2c 100644 --- a/sys/pc98/i386/machdep.c +++ b/sys/pc98/i386/machdep.c @@ -132,6 +132,7 @@ #include <machine/vm86.h> #include <machine/random.h> #include <sys/ptrace.h> +#include <machine/sigframe.h> extern void init386 __P((int first)); extern void dblfault_handler __P((void)); @@ -484,79 +485,66 @@ netisr_sysinit(data) * frame pointer, it returns to the user * specified pc, psl. */ -void -sendsig(catcher, sig, mask, code) - sig_t catcher; - int sig, mask; - u_long code; +static void +osendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) { register struct proc *p = curproc; register struct trapframe *regs; - register struct sigframe *fp; - struct sigframe sf; + register struct osigframe *fp; + struct osigframe sf; struct sigacts *psp = p->p_sigacts; int oonstack; regs = p->p_md.md_regs; - oonstack = psp->ps_sigstk.ss_flags & SS_ONSTACK; - /* - * Allocate and validate space for the signal handler context. - */ - if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack && - (psp->ps_sigonstack & sigmask(sig))) { - fp = (struct sigframe *)(psp->ps_sigstk.ss_sp + - psp->ps_sigstk.ss_size - sizeof(struct sigframe)); + oonstack = (psp->ps_sigstk.ss_flags & SS_ONSTACK) ? 1 : 0; + + /* Allocate and validate space for the signal handler context. */ + if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack && + SIGISMEMBER(psp->ps_sigonstack, sig)) { + fp = (struct osigframe *)(psp->ps_sigstk.ss_sp + + psp->ps_sigstk.ss_size - sizeof(struct osigframe)); psp->ps_sigstk.ss_flags |= SS_ONSTACK; - } else { - fp = (struct sigframe *)regs->tf_esp - 1; } + else + fp = (struct osigframe *)regs->tf_esp - 1; /* * grow() will return FALSE if the fp will not fit inside the stack * and the stack can not be grown. useracc will return FALSE * if access is denied. */ - if ((grow_stack (p, (int)fp) == FALSE) || - (useracc((caddr_t)fp, sizeof(struct sigframe), B_WRITE) == FALSE)) { + if (grow_stack(p, (int)fp) == FALSE || + useracc((caddr_t)fp, sizeof(struct osigframe), B_WRITE) == FALSE) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ -#ifdef DEBUG - printf("process %d has trashed its stack\n", p->p_pid); -#endif SIGACTION(p, SIGILL) = SIG_DFL; - sig = sigmask(SIGILL); - p->p_sigignore &= ~sig; - p->p_sigcatch &= ~sig; - p->p_sigmask &= ~sig; + SIGDELSET(p->p_sigignore, SIGILL); + SIGDELSET(p->p_sigcatch, SIGILL); + SIGDELSET(p->p_sigmask, SIGILL); psignal(p, SIGILL); return; } - /* - * Build the argument list for the signal handler. - */ + /* Translate the signal if appropriate */ if (p->p_sysent->sv_sigtbl) { - if (sig < p->p_sysent->sv_sigsize) - sig = p->p_sysent->sv_sigtbl[sig]; - else - sig = p->p_sysent->sv_sigsize + 1; + if (sig <= p->p_sysent->sv_sigsize) + sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; } + + /* Build the argument list for the signal handler. */ sf.sf_signum = sig; sf.sf_scp = (register_t)&fp->sf_siginfo.si_sc; - if (p->p_sigacts->ps_siginfo & sigmask(sig)) { - /* - * Signal handler installed with SA_SIGINFO. - */ + if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { + /* Signal handler installed with SA_SIGINFO. */ sf.sf_arg2 = (register_t)&fp->sf_siginfo; sf.sf_siginfo.si_signo = sig; sf.sf_siginfo.si_code = code; - sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; - } else { - /* - * Old FreeBSD-style arguments. - */ + sf.sf_ahu.sf_action = (__osiginfohandler_t *)catcher; + } + else { + /* Old FreeBSD-style arguments. */ sf.sf_arg2 = code; sf.sf_ahu.sf_handler = catcher; } @@ -578,11 +566,9 @@ sendsig(catcher, sig, mask, code) sf.sf_siginfo.si_sc.sc_gs = rgs(); sf.sf_siginfo.si_sc.sc_isp = regs->tf_isp; - /* - * Build the signal context to be used by sigreturn. - */ + /* Build the signal context to be used by sigreturn. */ sf.sf_siginfo.si_sc.sc_onstack = oonstack; - sf.sf_siginfo.si_sc.sc_mask = mask; + SIG2OSIG(*mask, sf.sf_siginfo.si_sc.sc_mask); sf.sf_siginfo.si_sc.sc_sp = regs->tf_esp; sf.sf_siginfo.si_sc.sc_fp = regs->tf_ebp; sf.sf_siginfo.si_sc.sc_pc = regs->tf_eip; @@ -605,8 +591,136 @@ sendsig(catcher, sig, mask, code) sf.sf_siginfo.si_sc.sc_ds = tf->tf_vm86_ds; if (vm86->vm86_has_vme == 0) - sf.sf_siginfo.si_sc.sc_ps = (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) + sf.sf_siginfo.si_sc.sc_ps = + (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) | (vm86->vm86_eflags & (PSL_VIF | PSL_VIP)); + /* see sendsig for comment */ + tf->tf_eflags &= ~(PSL_VM|PSL_NT|PSL_T|PSL_VIF|PSL_VIP); + } + + /* Copy the sigframe out to the user's stack. */ + if (copyout(&sf, fp, sizeof(struct osigframe)) != 0) { + /* + * Something is wrong with the stack pointer. + * ...Kill the process. + */ + sigexit(p, SIGILL); + } + + regs->tf_esp = (int)fp; + regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode); + regs->tf_cs = _ucodesel; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; + regs->tf_fs = _udatasel; + regs->tf_ss = _udatasel; +} + +void +sendsig(catcher, sig, mask, code) + sig_t catcher; + int sig; + sigset_t *mask; + u_long code; +{ + struct proc *p; + struct trapframe *regs; + struct sigacts *psp; + struct sigframe sf, *sfp; + + p = curproc; + + if ((p->p_flag & P_NEWSIGSET) == 0) { + osendsig(catcher, sig, mask, code); + return; + } + + regs = p->p_md.md_regs; + psp = p->p_sigacts; + + /* save user context */ + sf.sf_uc.uc_link = NULL; + sf.sf_uc.uc_sigmask = *mask; + sf.sf_uc.uc_stack = psp->ps_sigstk; + sf.sf_uc.uc_mcontext.mc_tf = *regs; + sf.sf_uc.uc_mcontext.mc_gs = rgs(); + + /* Allocate and validate space for the signal handler context. */ + if ((psp->ps_flags & SAS_ALTSTACK) != 0 && + (psp->ps_sigstk.ss_flags & SS_ONSTACK) == 0 && + SIGISMEMBER(psp->ps_sigonstack, sig)) { + sfp = (struct sigframe *)(psp->ps_sigstk.ss_sp + + psp->ps_sigstk.ss_size - sizeof(struct sigframe)); + psp->ps_sigstk.ss_flags |= SS_ONSTACK; + } + else + sfp = (struct sigframe *)regs->tf_esp - 1; + + /* + * grow() will return FALSE if the sfp will not fit inside the stack + * and the stack can not be grown. useracc will return FALSE if + * access is denied. + */ + if (grow_stack(p, (int)sfp) == FALSE || + useracc((caddr_t)sfp, sizeof(struct sigframe), B_WRITE) == FALSE) { + /* + * Process has trashed its stack; give it an illegal + * instruction to halt it in its tracks. + */ +#ifdef DEBUG + printf("process %d has trashed its stack\n", p->p_pid); +#endif + SIGACTION(p, SIGILL) = SIG_DFL; + SIGDELSET(p->p_sigignore, SIGILL); + SIGDELSET(p->p_sigcatch, SIGILL); + SIGDELSET(p->p_sigmask, SIGILL); + psignal(p, SIGILL); + return; + } + + /* Translate the signal is appropriate */ + if (p->p_sysent->sv_sigtbl) { + if (sig <= p->p_sysent->sv_sigsize) + sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; + } + + /* Build the argument list for the signal handler. */ + sf.sf_signum = sig; + sf.sf_ucontext = (register_t)&sfp->sf_uc; + if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { + /* Signal handler installed with SA_SIGINFO. */ + sf.sf_siginfo = (register_t)&sfp->sf_si; + sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; + + /* fill siginfo structure */ + sf.sf_si.si_signo = sig; + sf.sf_si.si_code = code; + sf.sf_si.si_pid = p->p_pid; + } + else { + /* Old FreeBSD-style arguments. */ + sf.sf_siginfo = code; + sf.sf_ahu.sf_handler = catcher; + } + + /* + * If we're a vm86 process, we want to save the segment registers. + * We also change eflags to be our emulated eflags, not the actual + * eflags. + */ + if (regs->tf_eflags & PSL_VM) { + struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; + struct vm86_kernel *vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; + + sf.sf_uc.uc_mcontext.mc_gs = tf->tf_vm86_gs; + sf.sf_uc.uc_mcontext.mc_tf.tf_fs = tf->tf_vm86_fs; + sf.sf_uc.uc_mcontext.mc_tf.tf_es = tf->tf_vm86_es; + sf.sf_uc.uc_mcontext.mc_tf.tf_ds = tf->tf_vm86_ds; + + if (vm86->vm86_has_vme == 0) + sf.sf_uc.uc_mcontext.mc_tf.tf_eflags = + (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) | + (vm86->vm86_eflags & (PSL_VIF | PSL_VIP)); /* * We should never have PSL_T set when returning from vm86 @@ -619,13 +733,15 @@ sendsig(catcher, sig, mask, code) * does nothing in vm86 mode, but vm86 programs can set it * almost legitimately in probes for old cpu types. */ - tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_T | PSL_VIF | PSL_VIP); + tf->tf_eflags &= ~(PSL_VM|PSL_NT|PSL_T|PSL_VIF|PSL_VIP); } + sf.sf_sigreturn = 0x0ABCDEF0; + /* * Copy the sigframe out to the user's stack. */ - if (copyout(&sf, fp, sizeof(struct sigframe)) != 0) { + if (copyout(&sf, sfp, sizeof(struct sigframe)) != 0) { /* * Something is wrong with the stack pointer. * ...Kill the process. @@ -633,7 +749,7 @@ sendsig(catcher, sig, mask, code) sigexit(p, SIGILL); } - regs->tf_esp = (int)fp; + regs->tf_esp = (int)sfp; regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode); regs->tf_cs = _ucodesel; regs->tf_ds = _udatasel; @@ -651,15 +767,18 @@ sendsig(catcher, sig, mask, code) * make sure that the user has not modified the * state to gain improper privileges. */ +#define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) +#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) + int -sigreturn(p, uap) +osigreturn(p, uap) struct proc *p; - struct sigreturn_args /* { - struct sigcontext *sigcntxp; + struct osigreturn_args /* { + struct osigcontext *sigcntxp; } */ *uap; { - register struct sigcontext *scp; - register struct sigframe *fp; + register struct osigcontext *scp; + register struct osigframe *fp; register struct trapframe *regs = p->p_md.md_regs; int eflags; @@ -670,10 +789,10 @@ sigreturn(p, uap) * for consistency. */ scp = uap->sigcntxp; - fp = (struct sigframe *) - ((caddr_t)scp - offsetof(struct sigframe, sf_siginfo.si_sc)); + fp = (struct osigframe *) + ((caddr_t)scp - offsetof(struct osigframe, sf_siginfo.si_sc)); - if (useracc((caddr_t)fp, sizeof (*fp), B_WRITE) == 0) + if (useracc((caddr_t)fp, sizeof (struct osigframe), B_WRITE) == 0) return(EFAULT); eflags = scp->sc_ps; @@ -713,7 +832,6 @@ sigreturn(p, uap) /* * Don't allow users to change privileged or reserved flags. */ -#define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) /* * XXX do allow users to change the privileged flag PSL_RF. * The cpu sets PSL_RF in tf_eflags for faults. Debuggers @@ -724,10 +842,7 @@ sigreturn(p, uap) * Corruption of the PSL_RF bit at worst causes one more or * one less debugger trap, so allowing it is fairly harmless. */ - if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { -#ifdef DEBUG - printf("sigreturn: eflags = 0x%x\n", eflags); -#endif + if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { return(EINVAL); } @@ -736,11 +851,7 @@ sigreturn(p, uap) * hardware check for invalid selectors, excess privilege in * other selectors, invalid %eip's and invalid %esp's. */ -#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) if (!CS_SECURE(scp->sc_cs)) { -#ifdef DEBUG - printf("sigreturn: cs = 0x%x\n", scp->sc_cs); -#endif trapsignal(p, SIGBUS, T_PROTFLT); return(EINVAL); } @@ -767,7 +878,9 @@ sigreturn(p, uap) p->p_sigacts->ps_sigstk.ss_flags |= SS_ONSTACK; else p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK; - p->p_sigmask = scp->sc_mask & ~sigcantmask; + + OSIG2SIG(scp->sc_mask, p->p_sigmask); + SIG_CANTMASK(p->p_sigmask); regs->tf_ebp = scp->sc_fp; regs->tf_esp = scp->sc_sp; regs->tf_eip = scp->sc_pc; @@ -775,6 +888,99 @@ sigreturn(p, uap) return(EJUSTRETURN); } +int +sigreturn(p, uap) + struct proc *p; + struct sigreturn_args /* { + ucontext_t *sigcntxp; + } */ *uap; +{ + struct trapframe *regs; + ucontext_t *ucp; + struct sigframe *sfp; + int eflags; + + regs = p->p_md.md_regs; + ucp = uap->sigcntxp; + sfp = (struct sigframe *) + ((caddr_t)ucp - offsetof(struct sigframe, sf_uc)); + eflags = ucp->uc_mcontext.mc_tf.tf_eflags; + + if (useracc((caddr_t)sfp, sizeof(struct sigframe), B_WRITE) == 0) + return(EFAULT); + + if (eflags & PSL_VM) { + struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; + struct vm86_kernel *vm86; + + /* + * if pcb_ext == 0 or vm86_inited == 0, the user hasn't + * set up the vm86 area, and we can't enter vm86 mode. + */ + if (p->p_addr->u_pcb.pcb_ext == 0) + return (EINVAL); + vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; + if (vm86->vm86_inited == 0) + return (EINVAL); + + /* go back to user mode if both flags are set */ + if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) + trapsignal(p, SIGBUS, 0); + + if (vm86->vm86_has_vme) { + eflags = (tf->tf_eflags & ~VME_USERCHANGE) | + (eflags & VME_USERCHANGE) | PSL_VM; + } else { + vm86->vm86_eflags = eflags; /* save VIF, VIP */ + eflags = (tf->tf_eflags & ~VM_USERCHANGE) | (eflags & VM_USERCHANGE) | PSL_VM; + } + *regs = ucp->uc_mcontext.mc_tf; + tf->tf_vm86_ds = tf->tf_ds; + tf->tf_vm86_es = tf->tf_es; + tf->tf_vm86_fs = tf->tf_fs; + tf->tf_vm86_gs = ucp->uc_mcontext.mc_gs; + tf->tf_ds = _udatasel; + tf->tf_es = _udatasel; + tf->tf_fs = _udatasel; + } else { + /* + * Don't allow users to change privileged or reserved flags. + */ + /* + * XXX do allow users to change the privileged flag PSL_RF. + * The cpu sets PSL_RF in tf_eflags for faults. Debuggers + * should sometimes set it there too. tf_eflags is kept in + * the signal context during signal handling and there is no + * other place to remember it, so the PSL_RF bit may be + * corrupted by the signal handler without us knowing. + * Corruption of the PSL_RF bit at worst causes one more or + * one less debugger trap, so allowing it is fairly harmless. + */ + if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { + printf("sigreturn: eflags = 0x%x\n", eflags); + return(EINVAL); + } + + *regs = ucp->uc_mcontext.mc_tf; + + /* + * Don't allow users to load a valid privileged %cs. Let the + * hardware check for invalid selectors, excess privilege in + * other selectors, invalid %eip's and invalid %esp's. + */ + if (!CS_SECURE(regs->tf_cs)) { + printf("sigreturn: cs = 0x%x\n", regs->tf_cs); + trapsignal(p, SIGBUS, T_PROTFLT); + return(EINVAL); + } + } + + p->p_sigacts->ps_sigstk = ucp->uc_stack; + p->p_sigmask = ucp->uc_sigmask; + SIG_CANTMASK(p->p_sigmask); + return(EJUSTRETURN); +} + /* * Machine dependent boot() routine * @@ -2098,7 +2304,7 @@ int ptrace_write_u(p, off, data) tp = p->p_md.md_regs; frame_copy = *tp; *(int *)((char *)&frame_copy + (off - min)) = data; - if (!EFLAGS_SECURE(frame_copy.tf_eflags, tp->tf_eflags) || + if (!EFL_SECURE(frame_copy.tf_eflags, tp->tf_eflags) || !CS_SECURE(frame_copy.tf_cs)) return (EINVAL); *(int*)((char *)p->p_addr + off) = data; @@ -2150,7 +2356,7 @@ set_regs(p, regs) struct trapframe *tp; tp = p->p_md.md_regs; - if (!EFLAGS_SECURE(regs->r_eflags, tp->tf_eflags) || + if (!EFL_SECURE(regs->r_eflags, tp->tf_eflags) || !CS_SECURE(regs->r_cs)) return (EINVAL); tp->tf_fs = regs->r_fs; diff --git a/sys/pc98/pc98/machdep.c b/sys/pc98/pc98/machdep.c index 93580f9..2bc0d2c 100644 --- a/sys/pc98/pc98/machdep.c +++ b/sys/pc98/pc98/machdep.c @@ -132,6 +132,7 @@ #include <machine/vm86.h> #include <machine/random.h> #include <sys/ptrace.h> +#include <machine/sigframe.h> extern void init386 __P((int first)); extern void dblfault_handler __P((void)); @@ -484,79 +485,66 @@ netisr_sysinit(data) * frame pointer, it returns to the user * specified pc, psl. */ -void -sendsig(catcher, sig, mask, code) - sig_t catcher; - int sig, mask; - u_long code; +static void +osendsig(sig_t catcher, int sig, sigset_t *mask, u_long code) { register struct proc *p = curproc; register struct trapframe *regs; - register struct sigframe *fp; - struct sigframe sf; + register struct osigframe *fp; + struct osigframe sf; struct sigacts *psp = p->p_sigacts; int oonstack; regs = p->p_md.md_regs; - oonstack = psp->ps_sigstk.ss_flags & SS_ONSTACK; - /* - * Allocate and validate space for the signal handler context. - */ - if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack && - (psp->ps_sigonstack & sigmask(sig))) { - fp = (struct sigframe *)(psp->ps_sigstk.ss_sp + - psp->ps_sigstk.ss_size - sizeof(struct sigframe)); + oonstack = (psp->ps_sigstk.ss_flags & SS_ONSTACK) ? 1 : 0; + + /* Allocate and validate space for the signal handler context. */ + if ((psp->ps_flags & SAS_ALTSTACK) && !oonstack && + SIGISMEMBER(psp->ps_sigonstack, sig)) { + fp = (struct osigframe *)(psp->ps_sigstk.ss_sp + + psp->ps_sigstk.ss_size - sizeof(struct osigframe)); psp->ps_sigstk.ss_flags |= SS_ONSTACK; - } else { - fp = (struct sigframe *)regs->tf_esp - 1; } + else + fp = (struct osigframe *)regs->tf_esp - 1; /* * grow() will return FALSE if the fp will not fit inside the stack * and the stack can not be grown. useracc will return FALSE * if access is denied. */ - if ((grow_stack (p, (int)fp) == FALSE) || - (useracc((caddr_t)fp, sizeof(struct sigframe), B_WRITE) == FALSE)) { + if (grow_stack(p, (int)fp) == FALSE || + useracc((caddr_t)fp, sizeof(struct osigframe), B_WRITE) == FALSE) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ -#ifdef DEBUG - printf("process %d has trashed its stack\n", p->p_pid); -#endif SIGACTION(p, SIGILL) = SIG_DFL; - sig = sigmask(SIGILL); - p->p_sigignore &= ~sig; - p->p_sigcatch &= ~sig; - p->p_sigmask &= ~sig; + SIGDELSET(p->p_sigignore, SIGILL); + SIGDELSET(p->p_sigcatch, SIGILL); + SIGDELSET(p->p_sigmask, SIGILL); psignal(p, SIGILL); return; } - /* - * Build the argument list for the signal handler. - */ + /* Translate the signal if appropriate */ if (p->p_sysent->sv_sigtbl) { - if (sig < p->p_sysent->sv_sigsize) - sig = p->p_sysent->sv_sigtbl[sig]; - else - sig = p->p_sysent->sv_sigsize + 1; + if (sig <= p->p_sysent->sv_sigsize) + sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; } + + /* Build the argument list for the signal handler. */ sf.sf_signum = sig; sf.sf_scp = (register_t)&fp->sf_siginfo.si_sc; - if (p->p_sigacts->ps_siginfo & sigmask(sig)) { - /* - * Signal handler installed with SA_SIGINFO. - */ + if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { + /* Signal handler installed with SA_SIGINFO. */ sf.sf_arg2 = (register_t)&fp->sf_siginfo; sf.sf_siginfo.si_signo = sig; sf.sf_siginfo.si_code = code; - sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; - } else { - /* - * Old FreeBSD-style arguments. - */ + sf.sf_ahu.sf_action = (__osiginfohandler_t *)catcher; + } + else { + /* Old FreeBSD-style arguments. */ sf.sf_arg2 = code; sf.sf_ahu.sf_handler = catcher; } @@ -578,11 +566,9 @@ sendsig(catcher, sig, mask, code) sf.sf_siginfo.si_sc.sc_gs = rgs(); sf.sf_siginfo.si_sc.sc_isp = regs->tf_isp; - /* - * Build the signal context to be used by sigreturn. - */ + /* Build the signal context to be used by sigreturn. */ sf.sf_siginfo.si_sc.sc_onstack = oonstack; - sf.sf_siginfo.si_sc.sc_mask = mask; + SIG2OSIG(*mask, sf.sf_siginfo.si_sc.sc_mask); sf.sf_siginfo.si_sc.sc_sp = regs->tf_esp; sf.sf_siginfo.si_sc.sc_fp = regs->tf_ebp; sf.sf_siginfo.si_sc.sc_pc = regs->tf_eip; @@ -605,8 +591,136 @@ sendsig(catcher, sig, mask, code) sf.sf_siginfo.si_sc.sc_ds = tf->tf_vm86_ds; if (vm86->vm86_has_vme == 0) - sf.sf_siginfo.si_sc.sc_ps = (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) + sf.sf_siginfo.si_sc.sc_ps = + (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) | (vm86->vm86_eflags & (PSL_VIF | PSL_VIP)); + /* see sendsig for comment */ + tf->tf_eflags &= ~(PSL_VM|PSL_NT|PSL_T|PSL_VIF|PSL_VIP); + } + + /* Copy the sigframe out to the user's stack. */ + if (copyout(&sf, fp, sizeof(struct osigframe)) != 0) { + /* + * Something is wrong with the stack pointer. + * ...Kill the process. + */ + sigexit(p, SIGILL); + } + + regs->tf_esp = (int)fp; + regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode); + regs->tf_cs = _ucodesel; + regs->tf_ds = _udatasel; + regs->tf_es = _udatasel; + regs->tf_fs = _udatasel; + regs->tf_ss = _udatasel; +} + +void +sendsig(catcher, sig, mask, code) + sig_t catcher; + int sig; + sigset_t *mask; + u_long code; +{ + struct proc *p; + struct trapframe *regs; + struct sigacts *psp; + struct sigframe sf, *sfp; + + p = curproc; + + if ((p->p_flag & P_NEWSIGSET) == 0) { + osendsig(catcher, sig, mask, code); + return; + } + + regs = p->p_md.md_regs; + psp = p->p_sigacts; + + /* save user context */ + sf.sf_uc.uc_link = NULL; + sf.sf_uc.uc_sigmask = *mask; + sf.sf_uc.uc_stack = psp->ps_sigstk; + sf.sf_uc.uc_mcontext.mc_tf = *regs; + sf.sf_uc.uc_mcontext.mc_gs = rgs(); + + /* Allocate and validate space for the signal handler context. */ + if ((psp->ps_flags & SAS_ALTSTACK) != 0 && + (psp->ps_sigstk.ss_flags & SS_ONSTACK) == 0 && + SIGISMEMBER(psp->ps_sigonstack, sig)) { + sfp = (struct sigframe *)(psp->ps_sigstk.ss_sp + + psp->ps_sigstk.ss_size - sizeof(struct sigframe)); + psp->ps_sigstk.ss_flags |= SS_ONSTACK; + } + else + sfp = (struct sigframe *)regs->tf_esp - 1; + + /* + * grow() will return FALSE if the sfp will not fit inside the stack + * and the stack can not be grown. useracc will return FALSE if + * access is denied. + */ + if (grow_stack(p, (int)sfp) == FALSE || + useracc((caddr_t)sfp, sizeof(struct sigframe), B_WRITE) == FALSE) { + /* + * Process has trashed its stack; give it an illegal + * instruction to halt it in its tracks. + */ +#ifdef DEBUG + printf("process %d has trashed its stack\n", p->p_pid); +#endif + SIGACTION(p, SIGILL) = SIG_DFL; + SIGDELSET(p->p_sigignore, SIGILL); + SIGDELSET(p->p_sigcatch, SIGILL); + SIGDELSET(p->p_sigmask, SIGILL); + psignal(p, SIGILL); + return; + } + + /* Translate the signal is appropriate */ + if (p->p_sysent->sv_sigtbl) { + if (sig <= p->p_sysent->sv_sigsize) + sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; + } + + /* Build the argument list for the signal handler. */ + sf.sf_signum = sig; + sf.sf_ucontext = (register_t)&sfp->sf_uc; + if (SIGISMEMBER(p->p_sigacts->ps_siginfo, sig)) { + /* Signal handler installed with SA_SIGINFO. */ + sf.sf_siginfo = (register_t)&sfp->sf_si; + sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; + + /* fill siginfo structure */ + sf.sf_si.si_signo = sig; + sf.sf_si.si_code = code; + sf.sf_si.si_pid = p->p_pid; + } + else { + /* Old FreeBSD-style arguments. */ + sf.sf_siginfo = code; + sf.sf_ahu.sf_handler = catcher; + } + + /* + * If we're a vm86 process, we want to save the segment registers. + * We also change eflags to be our emulated eflags, not the actual + * eflags. + */ + if (regs->tf_eflags & PSL_VM) { + struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; + struct vm86_kernel *vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; + + sf.sf_uc.uc_mcontext.mc_gs = tf->tf_vm86_gs; + sf.sf_uc.uc_mcontext.mc_tf.tf_fs = tf->tf_vm86_fs; + sf.sf_uc.uc_mcontext.mc_tf.tf_es = tf->tf_vm86_es; + sf.sf_uc.uc_mcontext.mc_tf.tf_ds = tf->tf_vm86_ds; + + if (vm86->vm86_has_vme == 0) + sf.sf_uc.uc_mcontext.mc_tf.tf_eflags = + (tf->tf_eflags & ~(PSL_VIF | PSL_VIP)) | + (vm86->vm86_eflags & (PSL_VIF | PSL_VIP)); /* * We should never have PSL_T set when returning from vm86 @@ -619,13 +733,15 @@ sendsig(catcher, sig, mask, code) * does nothing in vm86 mode, but vm86 programs can set it * almost legitimately in probes for old cpu types. */ - tf->tf_eflags &= ~(PSL_VM | PSL_NT | PSL_T | PSL_VIF | PSL_VIP); + tf->tf_eflags &= ~(PSL_VM|PSL_NT|PSL_T|PSL_VIF|PSL_VIP); } + sf.sf_sigreturn = 0x0ABCDEF0; + /* * Copy the sigframe out to the user's stack. */ - if (copyout(&sf, fp, sizeof(struct sigframe)) != 0) { + if (copyout(&sf, sfp, sizeof(struct sigframe)) != 0) { /* * Something is wrong with the stack pointer. * ...Kill the process. @@ -633,7 +749,7 @@ sendsig(catcher, sig, mask, code) sigexit(p, SIGILL); } - regs->tf_esp = (int)fp; + regs->tf_esp = (int)sfp; regs->tf_eip = PS_STRINGS - *(p->p_sysent->sv_szsigcode); regs->tf_cs = _ucodesel; regs->tf_ds = _udatasel; @@ -651,15 +767,18 @@ sendsig(catcher, sig, mask, code) * make sure that the user has not modified the * state to gain improper privileges. */ +#define EFL_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) +#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) + int -sigreturn(p, uap) +osigreturn(p, uap) struct proc *p; - struct sigreturn_args /* { - struct sigcontext *sigcntxp; + struct osigreturn_args /* { + struct osigcontext *sigcntxp; } */ *uap; { - register struct sigcontext *scp; - register struct sigframe *fp; + register struct osigcontext *scp; + register struct osigframe *fp; register struct trapframe *regs = p->p_md.md_regs; int eflags; @@ -670,10 +789,10 @@ sigreturn(p, uap) * for consistency. */ scp = uap->sigcntxp; - fp = (struct sigframe *) - ((caddr_t)scp - offsetof(struct sigframe, sf_siginfo.si_sc)); + fp = (struct osigframe *) + ((caddr_t)scp - offsetof(struct osigframe, sf_siginfo.si_sc)); - if (useracc((caddr_t)fp, sizeof (*fp), B_WRITE) == 0) + if (useracc((caddr_t)fp, sizeof (struct osigframe), B_WRITE) == 0) return(EFAULT); eflags = scp->sc_ps; @@ -713,7 +832,6 @@ sigreturn(p, uap) /* * Don't allow users to change privileged or reserved flags. */ -#define EFLAGS_SECURE(ef, oef) ((((ef) ^ (oef)) & ~PSL_USERCHANGE) == 0) /* * XXX do allow users to change the privileged flag PSL_RF. * The cpu sets PSL_RF in tf_eflags for faults. Debuggers @@ -724,10 +842,7 @@ sigreturn(p, uap) * Corruption of the PSL_RF bit at worst causes one more or * one less debugger trap, so allowing it is fairly harmless. */ - if (!EFLAGS_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { -#ifdef DEBUG - printf("sigreturn: eflags = 0x%x\n", eflags); -#endif + if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { return(EINVAL); } @@ -736,11 +851,7 @@ sigreturn(p, uap) * hardware check for invalid selectors, excess privilege in * other selectors, invalid %eip's and invalid %esp's. */ -#define CS_SECURE(cs) (ISPL(cs) == SEL_UPL) if (!CS_SECURE(scp->sc_cs)) { -#ifdef DEBUG - printf("sigreturn: cs = 0x%x\n", scp->sc_cs); -#endif trapsignal(p, SIGBUS, T_PROTFLT); return(EINVAL); } @@ -767,7 +878,9 @@ sigreturn(p, uap) p->p_sigacts->ps_sigstk.ss_flags |= SS_ONSTACK; else p->p_sigacts->ps_sigstk.ss_flags &= ~SS_ONSTACK; - p->p_sigmask = scp->sc_mask & ~sigcantmask; + + OSIG2SIG(scp->sc_mask, p->p_sigmask); + SIG_CANTMASK(p->p_sigmask); regs->tf_ebp = scp->sc_fp; regs->tf_esp = scp->sc_sp; regs->tf_eip = scp->sc_pc; @@ -775,6 +888,99 @@ sigreturn(p, uap) return(EJUSTRETURN); } +int +sigreturn(p, uap) + struct proc *p; + struct sigreturn_args /* { + ucontext_t *sigcntxp; + } */ *uap; +{ + struct trapframe *regs; + ucontext_t *ucp; + struct sigframe *sfp; + int eflags; + + regs = p->p_md.md_regs; + ucp = uap->sigcntxp; + sfp = (struct sigframe *) + ((caddr_t)ucp - offsetof(struct sigframe, sf_uc)); + eflags = ucp->uc_mcontext.mc_tf.tf_eflags; + + if (useracc((caddr_t)sfp, sizeof(struct sigframe), B_WRITE) == 0) + return(EFAULT); + + if (eflags & PSL_VM) { + struct trapframe_vm86 *tf = (struct trapframe_vm86 *)regs; + struct vm86_kernel *vm86; + + /* + * if pcb_ext == 0 or vm86_inited == 0, the user hasn't + * set up the vm86 area, and we can't enter vm86 mode. + */ + if (p->p_addr->u_pcb.pcb_ext == 0) + return (EINVAL); + vm86 = &p->p_addr->u_pcb.pcb_ext->ext_vm86; + if (vm86->vm86_inited == 0) + return (EINVAL); + + /* go back to user mode if both flags are set */ + if ((eflags & PSL_VIP) && (eflags & PSL_VIF)) + trapsignal(p, SIGBUS, 0); + + if (vm86->vm86_has_vme) { + eflags = (tf->tf_eflags & ~VME_USERCHANGE) | + (eflags & VME_USERCHANGE) | PSL_VM; + } else { + vm86->vm86_eflags = eflags; /* save VIF, VIP */ + eflags = (tf->tf_eflags & ~VM_USERCHANGE) | (eflags & VM_USERCHANGE) | PSL_VM; + } + *regs = ucp->uc_mcontext.mc_tf; + tf->tf_vm86_ds = tf->tf_ds; + tf->tf_vm86_es = tf->tf_es; + tf->tf_vm86_fs = tf->tf_fs; + tf->tf_vm86_gs = ucp->uc_mcontext.mc_gs; + tf->tf_ds = _udatasel; + tf->tf_es = _udatasel; + tf->tf_fs = _udatasel; + } else { + /* + * Don't allow users to change privileged or reserved flags. + */ + /* + * XXX do allow users to change the privileged flag PSL_RF. + * The cpu sets PSL_RF in tf_eflags for faults. Debuggers + * should sometimes set it there too. tf_eflags is kept in + * the signal context during signal handling and there is no + * other place to remember it, so the PSL_RF bit may be + * corrupted by the signal handler without us knowing. + * Corruption of the PSL_RF bit at worst causes one more or + * one less debugger trap, so allowing it is fairly harmless. + */ + if (!EFL_SECURE(eflags & ~PSL_RF, regs->tf_eflags & ~PSL_RF)) { + printf("sigreturn: eflags = 0x%x\n", eflags); + return(EINVAL); + } + + *regs = ucp->uc_mcontext.mc_tf; + + /* + * Don't allow users to load a valid privileged %cs. Let the + * hardware check for invalid selectors, excess privilege in + * other selectors, invalid %eip's and invalid %esp's. + */ + if (!CS_SECURE(regs->tf_cs)) { + printf("sigreturn: cs = 0x%x\n", regs->tf_cs); + trapsignal(p, SIGBUS, T_PROTFLT); + return(EINVAL); + } + } + + p->p_sigacts->ps_sigstk = ucp->uc_stack; + p->p_sigmask = ucp->uc_sigmask; + SIG_CANTMASK(p->p_sigmask); + return(EJUSTRETURN); +} + /* * Machine dependent boot() routine * @@ -2098,7 +2304,7 @@ int ptrace_write_u(p, off, data) tp = p->p_md.md_regs; frame_copy = *tp; *(int *)((char *)&frame_copy + (off - min)) = data; - if (!EFLAGS_SECURE(frame_copy.tf_eflags, tp->tf_eflags) || + if (!EFL_SECURE(frame_copy.tf_eflags, tp->tf_eflags) || !CS_SECURE(frame_copy.tf_cs)) return (EINVAL); *(int*)((char *)p->p_addr + off) = data; @@ -2150,7 +2356,7 @@ set_regs(p, regs) struct trapframe *tp; tp = p->p_md.md_regs; - if (!EFLAGS_SECURE(regs->r_eflags, tp->tf_eflags) || + if (!EFL_SECURE(regs->r_eflags, tp->tf_eflags) || !CS_SECURE(regs->r_cs)) return (EINVAL); tp->tf_fs = regs->r_fs; diff --git a/sys/powerpc/include/sigframe.h b/sys/powerpc/include/sigframe.h new file mode 100644 index 0000000..bc445a9 --- /dev/null +++ b/sys/powerpc/include/sigframe.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 1999 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_SIGFRAME_H_ +#define _MACHINE_SIGFRAME_H_ 1 + +struct osigframe { + struct osigcontext sf_sc; + osiginfo_t sf_si; +}; + +struct sigframe { + unsigned long __spare__; + ucontext_t sf_uc; + siginfo_t sf_si; +}; + +#endif /* _MACHINE_SIGFRAME_H_ */ |