diff options
author | marcel <marcel@FreeBSD.org> | 1999-09-29 15:06:27 +0000 |
---|---|---|
committer | marcel <marcel@FreeBSD.org> | 1999-09-29 15:06:27 +0000 |
commit | a16d76cb5680cf0afd1a3be9be9d1f7ea686a96c (patch) | |
tree | 01641d7a39068193783b082ecaf28021e39ce36c /sys/amd64 | |
parent | d5e8d714b93b1824409b762780bec45541995276 (diff) | |
download | FreeBSD-src-a16d76cb5680cf0afd1a3be9be9d1f7ea686a96c.zip FreeBSD-src-a16d76cb5680cf0afd1a3be9be9d1f7ea686a96c.tar.gz |
sigset_t change (part 3 of 5)
-----------------------------
By introducing a new sigframe so that the signal handler operates
on the new siginfo_t and on ucontext_t instead of sigcontext, we
now need two version of sendsig and sigreturn.
A flag in struct proc determines whether the process expects an
old sigframe or a new sigframe. The signal trampoline handles
which sigreturn to call. It does this by testing for a magic
cookie in the frame.
The alpha uses osigreturn to implement longjmp. This means that
osigreturn is not only used for compatibility with existing
binaries. To handle the new sigset_t, setjmp saves it in
sc_reserved (see NOTE).
the struct sigframe has been moved from frame.h to sigframe.h
to handle the complex header dependencies that was caused by
the new sigframe.
NOTE: For the i386, the size of jmp_buf has been increased to hold
the new sigset_t. On the alpha this has been prevented by
using sc_reserved in sigcontext.
Diffstat (limited to 'sys/amd64')
-rw-r--r-- | sys/amd64/amd64/genassym.c | 16 | ||||
-rw-r--r-- | sys/amd64/amd64/locore.S | 38 | ||||
-rw-r--r-- | sys/amd64/amd64/locore.s | 38 | ||||
-rw-r--r-- | sys/amd64/amd64/machdep.c | 345 | ||||
-rw-r--r-- | sys/amd64/include/db_machdep.h | 1 | ||||
-rw-r--r-- | sys/amd64/include/frame.h | 38 | ||||
-rw-r--r-- | sys/amd64/include/setjmp.h | 2 | ||||
-rw-r--r-- | sys/amd64/include/sigframe.h | 86 | ||||
-rw-r--r-- | sys/amd64/include/signal.h | 56 | ||||
-rw-r--r-- | sys/amd64/include/ucontext.h | 43 |
10 files changed, 505 insertions, 158 deletions
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_ */ |