Messages in this thread Patch in this message | | | Date | Mon, 8 Jun 1998 18:26:01 -0700 | From | Richard Henderson <> | Subject | Re: patch for sigaltstack |
| |
On Sun, Jun 07, 1998 at 09:00:23PM -0700, Richard Henderson wrote: > Revert the patch and I'll give you another with this corrected.
As promised.
r~
diff -rup 2.1.105/arch/alpha/kernel/entry.S 2.1.105-rth/arch/alpha/kernel/entry.S --- 2.1.105/arch/alpha/kernel/entry.S Mon Jun 8 00:29:53 1998 +++ 2.1.105-rth/arch/alpha/kernel/entry.S Sun Jun 7 21:53:50 1998 @@ -924,7 +924,7 @@ sys_call_table: .quad alpha_ni_syscall .quad alpha_ni_syscall /* 110 */ .quad sys_sigsuspend - .quad sys_ni_syscall + .quad osf_sigstack .quad sys_recvmsg .quad sys_sendmsg .quad alpha_ni_syscall /* 115 */ @@ -1047,7 +1047,7 @@ sys_call_table: .quad alpha_ni_syscall .quad sys_getpgid .quad sys_getsid - .quad alpha_ni_syscall /* 235 */ + .quad sys_sigaltstack /* 235 */ .quad alpha_ni_syscall .quad alpha_ni_syscall .quad alpha_ni_syscall diff -rup 2.1.105/arch/alpha/kernel/osf_sys.c 2.1.105-rth/arch/alpha/kernel/osf_sys.c --- 2.1.105/arch/alpha/kernel/osf_sys.c Thu Apr 9 03:56:55 1998 +++ 2.1.105-rth/arch/alpha/kernel/osf_sys.c Mon Jun 8 10:35:15 1998 @@ -743,6 +743,50 @@ asmlinkage long osf_proplist_syscall(enu return error; } +asmlinkage int osf_sigstack(struct sigstack *uss, struct sigstack *uoss) +{ + unsigned long usp = rdusp(); + unsigned long oss_sp, oss_os; + int error; + + if (uoss) { + oss_sp = current->sas_ss_sp + current->sas_ss_size; + oss_os = on_sig_stack(usp); + } + + if (uss) { + unsigned long ss_sp; + + error = -EFAULT; + if (get_user(ss_sp, &uss->ss_sp)) + goto out; + + /* If the current stack was set with sigaltstack, don't + swap stacks while we are on it. */ + error = -EPERM; + if (current->sas_ss_sp && on_sig_stack(usp)) + goto out; + + /* Since we don't know the extent of the stack, and we don't + track onstack-ness, but rather calculate it, we must + presume a size. Ho hum this interface is lossy. */ + current->sas_ss_sp = ss_sp - SIGSTKSZ; + current->sas_ss_size = SIGSTKSZ; + } + + if (uoss) { + error = -EFAULT; + if (! access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)) + || __put_user(oss_sp, &uoss->ss_sp) + || __put_user(oss_os, &uoss->ss_onstack)) + goto out; + } + + error = 0; +out: + return error; +} + /* * The Linux kernel isn't good at returning values that look * like negative longs (they are mistaken as error values). diff -rup 2.1.105/arch/alpha/kernel/signal.c 2.1.105-rth/arch/alpha/kernel/signal.c --- 2.1.105/arch/alpha/kernel/signal.c Thu Feb 5 14:39:40 1998 +++ 2.1.105-rth/arch/alpha/kernel/signal.c Mon Jun 8 12:01:29 1998 @@ -203,6 +203,12 @@ do_rt_sigsuspend(sigset_t *uset, size_t } } +asmlinkage int +sys_sigaltstack(const stack_t *uss, stack_t *uoss) +{ + return do_sigaltstack(uss, uoss, rdusp()); +} + /* * Do a signal return; undo the signal stack. */ @@ -225,67 +231,65 @@ struct rt_sigframe #define INSN_LDI_R0 0x201f0000 #define INSN_CALLSYS 0x00000083 - -static void +static long restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs, struct switch_stack *sw) { unsigned long usp; - int i; + long i, err = 0; - __get_user(regs->pc, &sc->sc_pc); + err |= __get_user(regs->pc, &sc->sc_pc); sw->r26 = (unsigned long) ret_from_sys_call; - __get_user(regs->r0, sc->sc_regs+0); - __get_user(regs->r1, sc->sc_regs+1); - __get_user(regs->r2, sc->sc_regs+2); - __get_user(regs->r3, sc->sc_regs+3); - __get_user(regs->r4, sc->sc_regs+4); - __get_user(regs->r5, sc->sc_regs+5); - __get_user(regs->r6, sc->sc_regs+6); - __get_user(regs->r7, sc->sc_regs+7); - __get_user(regs->r8, sc->sc_regs+8); - __get_user(sw->r9, sc->sc_regs+9); - __get_user(sw->r10, sc->sc_regs+10); - __get_user(sw->r11, sc->sc_regs+11); - __get_user(sw->r12, sc->sc_regs+12); - __get_user(sw->r13, sc->sc_regs+13); - __get_user(sw->r14, sc->sc_regs+14); - __get_user(sw->r15, sc->sc_regs+15); - __get_user(regs->r16, sc->sc_regs+16); - __get_user(regs->r17, sc->sc_regs+17); - __get_user(regs->r18, sc->sc_regs+18); - __get_user(regs->r19, sc->sc_regs+19); - __get_user(regs->r20, sc->sc_regs+20); - __get_user(regs->r21, sc->sc_regs+21); - __get_user(regs->r22, sc->sc_regs+22); - __get_user(regs->r23, sc->sc_regs+23); - __get_user(regs->r24, sc->sc_regs+24); - __get_user(regs->r25, sc->sc_regs+25); - __get_user(regs->r26, sc->sc_regs+26); - __get_user(regs->r27, sc->sc_regs+27); - __get_user(regs->r28, sc->sc_regs+28); - __get_user(regs->gp, sc->sc_regs+29); - __get_user(usp, sc->sc_regs+30); + err |= __get_user(regs->r0, sc->sc_regs+0); + err |= __get_user(regs->r1, sc->sc_regs+1); + err |= __get_user(regs->r2, sc->sc_regs+2); + err |= __get_user(regs->r3, sc->sc_regs+3); + err |= __get_user(regs->r4, sc->sc_regs+4); + err |= __get_user(regs->r5, sc->sc_regs+5); + err |= __get_user(regs->r6, sc->sc_regs+6); + err |= __get_user(regs->r7, sc->sc_regs+7); + err |= __get_user(regs->r8, sc->sc_regs+8); + err |= __get_user(sw->r9, sc->sc_regs+9); + err |= __get_user(sw->r10, sc->sc_regs+10); + err |= __get_user(sw->r11, sc->sc_regs+11); + err |= __get_user(sw->r12, sc->sc_regs+12); + err |= __get_user(sw->r13, sc->sc_regs+13); + err |= __get_user(sw->r14, sc->sc_regs+14); + err |= __get_user(sw->r15, sc->sc_regs+15); + err |= __get_user(regs->r16, sc->sc_regs+16); + err |= __get_user(regs->r17, sc->sc_regs+17); + err |= __get_user(regs->r18, sc->sc_regs+18); + err |= __get_user(regs->r19, sc->sc_regs+19); + err |= __get_user(regs->r20, sc->sc_regs+20); + err |= __get_user(regs->r21, sc->sc_regs+21); + err |= __get_user(regs->r22, sc->sc_regs+22); + err |= __get_user(regs->r23, sc->sc_regs+23); + err |= __get_user(regs->r24, sc->sc_regs+24); + err |= __get_user(regs->r25, sc->sc_regs+25); + err |= __get_user(regs->r26, sc->sc_regs+26); + err |= __get_user(regs->r27, sc->sc_regs+27); + err |= __get_user(regs->r28, sc->sc_regs+28); + err |= __get_user(regs->gp, sc->sc_regs+29); + err |= __get_user(usp, sc->sc_regs+30); wrusp(usp); for (i = 0; i < 31; i++) - __get_user(sw->fp[i], sc->sc_fpregs+i); - __get_user(sw->fp[31], &sc->sc_fpcr); + err |= __get_user(sw->fp[i], sc->sc_fpregs+i); + err |= __get_user(sw->fp[31], &sc->sc_fpcr); + + return err; } asmlinkage void do_sigreturn(struct sigframe *frame, struct pt_regs *regs, struct switch_stack *sw) { - unsigned long ps; sigset_t set; /* Verify that it's a good sigcontext before using it */ if (verify_area(VERIFY_READ, frame, sizeof(*frame))) goto give_sigsegv; - if (__get_user(ps, &frame->sc.sc_ps) || ps != 8) - goto give_sigsegv; if (__get_user(set.sig[0], &frame->sc.sc_mask) || (_NSIG_WORDS > 1 && __copy_from_user(&set.sig[1], &frame->extramask, @@ -298,7 +302,8 @@ do_sigreturn(struct sigframe *frame, str recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); - restore_sigcontext(&frame->sc, regs, sw); + if (restore_sigcontext(&frame->sc, regs, sw)) + goto give_sigsegv; /* Send SIGTRAP if we're single-stepping: */ if (ptrace_cancel_bpt (current)) @@ -306,22 +311,19 @@ do_sigreturn(struct sigframe *frame, str return; give_sigsegv: - lock_kernel(); - do_exit(SIGSEGV); + send_sig(SIGSEGV, current, 1); } asmlinkage void do_rt_sigreturn(struct rt_sigframe *frame, struct pt_regs *regs, struct switch_stack *sw) { - unsigned long ps; sigset_t set; + stack_t st; /* Verify that it's a good sigcontext before using it */ if (verify_area(VERIFY_READ, frame, sizeof(*frame))) goto give_sigsegv; - if (__get_user(ps, &frame->uc.uc_mcontext.sc_ps) || ps != 8) - goto give_sigsegv; if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) goto give_sigsegv; @@ -331,7 +333,14 @@ do_rt_sigreturn(struct rt_sigframe *fram recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); - restore_sigcontext(&frame->uc.uc_mcontext, regs, sw); + if (restore_sigcontext(&frame->uc.uc_mcontext, regs, sw)) + goto give_sigsegv; + + if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) + goto give_sigsegv; + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + do_sigaltstack(&st, NULL, rdusp()); /* Send SIGTRAP if we're single-stepping: */ if (ptrace_cancel_bpt (current)) @@ -339,8 +348,7 @@ do_rt_sigreturn(struct rt_sigframe *fram return; give_sigsegv: - lock_kernel(); - do_exit(SIGSEGV); + send_sig(SIGSEGV, current, 1); } @@ -348,99 +356,113 @@ give_sigsegv: * Set up a signal frame. */ -static void +static inline void * +get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size) +{ + if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp)) + sp = current->sas_ss_sp + current->sas_ss_size; + + return (void *)((sp - frame_size) & -32ul); +} + +static long setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, struct switch_stack *sw, unsigned long mask, unsigned long sp) { - long i; + long i, err = 0; - __put_user(0, &sc->sc_onstack); - __put_user(mask, &sc->sc_mask); - __put_user(regs->pc, &sc->sc_pc); - __put_user(8, &sc->sc_ps); - - __put_user(regs->r0 , sc->sc_regs+0); - __put_user(regs->r1 , sc->sc_regs+1); - __put_user(regs->r2 , sc->sc_regs+2); - __put_user(regs->r3 , sc->sc_regs+3); - __put_user(regs->r4 , sc->sc_regs+4); - __put_user(regs->r5 , sc->sc_regs+5); - __put_user(regs->r6 , sc->sc_regs+6); - __put_user(regs->r7 , sc->sc_regs+7); - __put_user(regs->r8 , sc->sc_regs+8); - __put_user(sw->r9 , sc->sc_regs+9); - __put_user(sw->r10 , sc->sc_regs+10); - __put_user(sw->r11 , sc->sc_regs+11); - __put_user(sw->r12 , sc->sc_regs+12); - __put_user(sw->r13 , sc->sc_regs+13); - __put_user(sw->r14 , sc->sc_regs+14); - __put_user(sw->r15 , sc->sc_regs+15); - __put_user(regs->r16, sc->sc_regs+16); - __put_user(regs->r17, sc->sc_regs+17); - __put_user(regs->r18, sc->sc_regs+18); - __put_user(regs->r19, sc->sc_regs+19); - __put_user(regs->r20, sc->sc_regs+20); - __put_user(regs->r21, sc->sc_regs+21); - __put_user(regs->r22, sc->sc_regs+22); - __put_user(regs->r23, sc->sc_regs+23); - __put_user(regs->r24, sc->sc_regs+24); - __put_user(regs->r25, sc->sc_regs+25); - __put_user(regs->r26, sc->sc_regs+26); - __put_user(regs->r27, sc->sc_regs+27); - __put_user(regs->r28, sc->sc_regs+28); - __put_user(regs->gp , sc->sc_regs+29); - __put_user(sp, sc->sc_regs+30); - __put_user(0, sc->sc_regs+31); + err |= __put_user(on_sig_stack((unsigned long)sc), &sc->sc_onstack); + err |= __put_user(mask, &sc->sc_mask); + err |= __put_user(regs->pc, &sc->sc_pc); + err |= __put_user(8, &sc->sc_ps); + + err |= __put_user(regs->r0 , sc->sc_regs+0); + err |= __put_user(regs->r1 , sc->sc_regs+1); + err |= __put_user(regs->r2 , sc->sc_regs+2); + err |= __put_user(regs->r3 , sc->sc_regs+3); + err |= __put_user(regs->r4 , sc->sc_regs+4); + err |= __put_user(regs->r5 , sc->sc_regs+5); + err |= __put_user(regs->r6 , sc->sc_regs+6); + err |= __put_user(regs->r7 , sc->sc_regs+7); + err |= __put_user(regs->r8 , sc->sc_regs+8); + err |= __put_user(sw->r9 , sc->sc_regs+9); + err |= __put_user(sw->r10 , sc->sc_regs+10); + err |= __put_user(sw->r11 , sc->sc_regs+11); + err |= __put_user(sw->r12 , sc->sc_regs+12); + err |= __put_user(sw->r13 , sc->sc_regs+13); + err |= __put_user(sw->r14 , sc->sc_regs+14); + err |= __put_user(sw->r15 , sc->sc_regs+15); + err |= __put_user(regs->r16, sc->sc_regs+16); + err |= __put_user(regs->r17, sc->sc_regs+17); + err |= __put_user(regs->r18, sc->sc_regs+18); + err |= __put_user(regs->r19, sc->sc_regs+19); + err |= __put_user(regs->r20, sc->sc_regs+20); + err |= __put_user(regs->r21, sc->sc_regs+21); + err |= __put_user(regs->r22, sc->sc_regs+22); + err |= __put_user(regs->r23, sc->sc_regs+23); + err |= __put_user(regs->r24, sc->sc_regs+24); + err |= __put_user(regs->r25, sc->sc_regs+25); + err |= __put_user(regs->r26, sc->sc_regs+26); + err |= __put_user(regs->r27, sc->sc_regs+27); + err |= __put_user(regs->r28, sc->sc_regs+28); + err |= __put_user(regs->gp , sc->sc_regs+29); + err |= __put_user(sp, sc->sc_regs+30); + err |= __put_user(0, sc->sc_regs+31); for (i = 0; i < 31; i++) - __put_user(sw->fp[i], sc->sc_fpregs+i); - __put_user(0, sc->sc_fpregs+31); - __put_user(sw->fp[31], &sc->sc_fpcr); - - __put_user(regs->trap_a0, &sc->sc_traparg_a0); - __put_user(regs->trap_a1, &sc->sc_traparg_a1); - __put_user(regs->trap_a2, &sc->sc_traparg_a2); + err |= __put_user(sw->fp[i], sc->sc_fpregs+i); + err |= __put_user(0, sc->sc_fpregs+31); + err |= __put_user(sw->fp[31], &sc->sc_fpcr); + + err |= __put_user(regs->trap_a0, &sc->sc_traparg_a0); + err |= __put_user(regs->trap_a1, &sc->sc_traparg_a1); + err |= __put_user(regs->trap_a2, &sc->sc_traparg_a2); + + return err; } static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs, struct switch_stack * sw) { - unsigned long oldsp; + unsigned long oldsp, r26, err = 0; struct sigframe *frame; oldsp = rdusp(); - frame = (struct sigframe *)((oldsp - sizeof(*frame)) & -32); - - /* XXX: Check here if we would need to switch stacks.. */ + frame = get_sigframe(ka, oldsp, sizeof(*frame)); if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; - setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp); + err |= setup_sigcontext(&frame->sc, regs, sw, set->sig[0], oldsp); if (_NSIG_WORDS > 1) { - __copy_to_user(frame->extramask, &set->sig[1], - sizeof(frame->extramask)); + err |= __copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); } /* Set up to return from userspace. If provided, use a stub already in userspace. */ if (ka->ka_restorer) { - regs->r26 = (unsigned long) ka->ka_restorer; + r26 = (unsigned long) ka->ka_restorer; } else { - __put_user(INSN_MOV_R30_R16, frame->retcode+0); - __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1); - __put_user(INSN_CALLSYS, frame->retcode+2); + err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0); + err |= __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1); + err |= __put_user(INSN_CALLSYS, frame->retcode+2); imb(); - regs->r26 = (unsigned long) frame->retcode; + r26 = (unsigned long) frame->retcode; } + /* Check that everything was written properly. */ + if (err) + goto give_sigsegv; + /* "Return" to the handler */ + regs->r26 = r26; regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler; regs->r16 = sig; /* a0: signal number */ regs->r17 = 0; /* a1: exception code */ regs->r18 = (unsigned long) &frame->sc; /* a2: sigcontext pointer */ wrusp((unsigned long) frame); - + #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", current->comm, current->pid, frame, regs->pc, regs->r26); @@ -449,47 +471,55 @@ setup_frame(int sig, struct k_sigaction return; give_sigsegv: - lock_kernel(); - do_exit(SIGSEGV); + if (sig == SIGSEGV) + force_sig(SIGSEGV, current); + else + send_sig(SIGSEGV, current, 1); } static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs, struct switch_stack * sw) { - unsigned long oldsp; + unsigned long oldsp, r26, err = 0; struct rt_sigframe *frame; oldsp = rdusp(); - frame = (struct rt_sigframe *)((oldsp - sizeof(*frame)) & -32); - - /* XXX: Check here if we would need to switch stacks.. */ + frame = get_sigframe(ka, oldsp, sizeof(*frame)); if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; - __copy_to_user(&frame->info, info, sizeof(siginfo_t)); + err |= __copy_to_user(&frame->info, info, sizeof(siginfo_t)); - /* Zero all bits of the ucontext besides the sigcontext. */ - __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); - - /* Copy in the bits we actually use. */ - __put_user(set->sig[0], &frame->uc.uc_osf_sigmask); - setup_sigcontext(&frame->uc.uc_mcontext, regs, sw, set->sig[0], oldsp); - __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= __put_user(set->sig[0], &frame->uc.uc_osf_sigmask); + err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(oldsp), &frame->uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, sw, + set->sig[0], oldsp); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); /* Set up to return from userspace. If provided, use a stub already in userspace. */ if (ka->ka_restorer) { - regs->r26 = (unsigned long) ka->ka_restorer; + r26 = (unsigned long) ka->ka_restorer; } else { - __put_user(INSN_MOV_R30_R16, frame->retcode+0); - __put_user(INSN_LDI_R0+__NR_rt_sigreturn, frame->retcode+1); - __put_user(INSN_CALLSYS, frame->retcode+2); + err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0); + err |= __put_user(INSN_LDI_R0+__NR_rt_sigreturn, + frame->retcode+1); + err |= __put_user(INSN_CALLSYS, frame->retcode+2); imb(); - regs->r26 = (unsigned long) frame->retcode; + r26 = (unsigned long) frame->retcode; } + if (err) + goto give_sigsegv; + /* "Return" to the handler */ + regs->r26 = r26; regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler; regs->r16 = sig; /* a0: signal number */ regs->r17 = (unsigned long) &frame->info; /* a1: siginfo pointer */ @@ -504,8 +534,10 @@ setup_rt_frame(int sig, struct k_sigacti return; give_sigsegv: - lock_kernel(); - do_exit(SIGSEGV); + if (sig == SIGSEGV) + force_sig(SIGSEGV, current); + else + send_sig(SIGSEGV, current, 1); } diff -rup 2.1.105/arch/i386/kernel/entry.S 2.1.105-rth/arch/i386/kernel/entry.S --- 2.1.105/arch/i386/kernel/entry.S Thu Jun 4 23:45:07 1998 +++ 2.1.105-rth/arch/i386/kernel/entry.S Sun Jun 7 21:53:50 1998 @@ -546,7 +546,8 @@ ENTRY(sys_call_table) .long SYMBOL_NAME(sys_getcwd) .long SYMBOL_NAME(sys_capget) .long SYMBOL_NAME(sys_capset) /* 185 */ + .long SYMBOL_NAME(sys_sigaltstack) - .rept NR_syscalls-185 + .rept NR_syscalls-186 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -rup 2.1.105/arch/i386/kernel/signal.c 2.1.105-rth/arch/i386/kernel/signal.c --- 2.1.105/arch/i386/kernel/signal.c Thu Apr 9 03:57:56 1998 +++ 2.1.105-rth/arch/i386/kernel/signal.c Mon Jun 8 11:59:18 1998 @@ -116,6 +116,13 @@ sys_sigaction(int sig, const struct old_ return ret; } +asmlinkage int +sys_sigaltstack(const stack_t *uss, stack_t *uoss) +{ + struct pt_regs *regs = (struct pt_regs *) &uss; + return do_sigaltstack(uss, uoss, regs->esp); +} + /* * Do a signal return; undo the signal stack. @@ -144,7 +151,7 @@ struct rt_sigframe }; -static inline void restore_i387_hard(struct _fpstate *buf) +static inline int restore_i387_hard(struct _fpstate *buf) { #ifdef __SMP__ if (current->flags & PF_USEDFPU) { @@ -157,31 +164,33 @@ static inline void restore_i387_hard(str } #endif current->flags &= ~PF_USEDFPU; - __copy_from_user(¤t->tss.i387.hard, buf, sizeof(*buf)); + return __copy_from_user(¤t->tss.i387.hard, buf, sizeof(*buf)); } -static inline void restore_i387(struct _fpstate *buf) +static inline int restore_i387(struct _fpstate *buf) { + int err; #ifndef CONFIG_MATH_EMULATION - restore_i387_hard(buf); + err = restore_i387_hard(buf); #else if (boot_cpu_data.hard_math) - restore_i387_hard(buf); + err = restore_i387_hard(buf); else - restore_i387_soft(¤t->tss.i387.soft, buf); + err = restore_i387_soft(¤t->tss.i387.soft, buf); #endif current->used_math = 1; + return err; } static int -restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) +restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *peax) { - unsigned int tmp; + unsigned int tmp, err = 0; -#define COPY(x) __get_user(regs->x, &sc->x) +#define COPY(x) err |= __get_user(regs->x, &sc->x) #define COPY_SEG(seg) \ - { __get_user(tmp, &sc->seg); \ + { err |= __get_user(tmp, &sc->seg); \ if ((tmp & 0xfffc) /* not a NULL selectors */ \ && (tmp & 0x4) != 0x4 /* not a LDT selector */ \ && (tmp & 3) != 3) /* not a RPL3 GDT selector */ \ @@ -189,12 +198,12 @@ restore_sigcontext(struct pt_regs *regs, regs->x##seg = tmp; } #define COPY_SEG_STRICT(seg) \ - { __get_user(tmp, &sc->seg); \ + { err |= __get_user(tmp, &sc->seg); \ if ((tmp & 0xfffc) && (tmp & 3) != 3) goto badframe; \ regs->x##seg = tmp; } #define GET_SEG(seg) \ - { __get_user(tmp, &sc->seg); \ + { err |= __get_user(tmp, &sc->seg); \ if ((tmp & 0xfffc) /* not a NULL selectors */ \ && (tmp & 0x4) != 0x4 /* not a LDT selector */ \ && (tmp & 3) != 3) /* not a RPL3 GDT selector */ \ @@ -216,24 +225,23 @@ restore_sigcontext(struct pt_regs *regs, COPY_SEG_STRICT(cs); COPY_SEG_STRICT(ss); - __get_user(tmp, &sc->eflags); + err |= __get_user(tmp, &sc->eflags); regs->eflags = (regs->eflags & ~0x40DD5) | (tmp & 0x40DD5); regs->orig_eax = -1; /* disable syscall checks */ - __get_user(tmp, (unsigned long *)&sc->fpstate); + err |= __get_user(tmp, (unsigned long *)&sc->fpstate); if (tmp) { struct _fpstate * buf = (struct _fpstate *) tmp; if (verify_area(VERIFY_READ, buf, sizeof(*buf))) goto badframe; - restore_i387(buf); + err |= restore_i387(buf); } - __get_user(tmp, &sc->eax); - return tmp; + err |= __get_user(*peax, &sc->eax); + return err; badframe: - lock_kernel(); - do_exit(SIGSEGV); + return 1; } asmlinkage int sys_sigreturn(unsigned long __unused) @@ -241,6 +249,7 @@ asmlinkage int sys_sigreturn(unsigned lo struct pt_regs *regs = (struct pt_regs *) &__unused; struct sigframe *frame = (struct sigframe *)(regs->esp - 8); sigset_t set; + int eax; if (verify_area(VERIFY_READ, frame, sizeof(*frame))) goto badframe; @@ -256,11 +265,13 @@ asmlinkage int sys_sigreturn(unsigned lo recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); - return restore_sigcontext(regs, &frame->sc); + if (restore_sigcontext(regs, &frame->sc, &eax)) + goto badframe; + return eax; badframe: - lock_kernel(); - do_exit(SIGSEGV); + send_sig(SIGSEGV, current, 1); + return 0; } asmlinkage int sys_rt_sigreturn(unsigned long __unused) @@ -268,6 +279,8 @@ asmlinkage int sys_rt_sigreturn(unsigned struct pt_regs *regs = (struct pt_regs *) &__unused; struct rt_sigframe *frame = (struct rt_sigframe *)(regs->esp - 4); sigset_t set; + stack_t st; + int eax; if (verify_area(VERIFY_READ, frame, sizeof(*frame))) goto badframe; @@ -280,18 +293,27 @@ asmlinkage int sys_rt_sigreturn(unsigned recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); - return restore_sigcontext(regs, &frame->uc.uc_mcontext); + if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &eax)) + goto badframe; + + if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) + goto badframe; + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + do_sigaltstack(&st, NULL, regs->esp); + + return eax; badframe: - lock_kernel(); - do_exit(SIGSEGV); + send_sig(SIGSEGV, current, 1); + return 0; } /* * Set up a signal frame. */ -static inline struct _fpstate * save_i387_hard(struct _fpstate * buf) +static inline int save_i387_hard(struct _fpstate * buf) { #ifdef __SMP__ if (current->flags & PF_USEDFPU) { @@ -308,14 +330,15 @@ static inline struct _fpstate * save_i38 } #endif current->tss.i387.hard.status = current->tss.i387.hard.swd; - copy_to_user(buf, ¤t->tss.i387.hard, sizeof(*buf)); - return buf; + if (__copy_to_user(buf, ¤t->tss.i387.hard, sizeof(*buf))) + return -1; + return 1; } -static struct _fpstate * save_i387(struct _fpstate *buf) +static int save_i387(struct _fpstate *buf) { if (!current->used_math) - return NULL; + return 0; /* This will cause a "finit" to be triggered by the next attempted FPU operation by the 'current' process. @@ -330,98 +353,116 @@ static struct _fpstate * save_i387(struc #endif } -static void +static int setup_sigcontext(struct sigcontext *sc, struct _fpstate *fpstate, struct pt_regs *regs, unsigned long mask) { - unsigned int tmp; + int tmp, err = 0; tmp = 0; __asm__("movl %%gs,%w0" : "=r"(tmp): "0"(tmp)); - __put_user(tmp, (unsigned int *)&sc->gs); + err |= __put_user(tmp, (unsigned int *)&sc->gs); __asm__("movl %%fs,%w0" : "=r"(tmp): "0"(tmp)); - __put_user(tmp, (unsigned int *)&sc->fs); - - __put_user(regs->xes, (unsigned int *)&sc->es); - __put_user(regs->xds, (unsigned int *)&sc->ds); - __put_user(regs->edi, &sc->edi); - __put_user(regs->esi, &sc->esi); - __put_user(regs->ebp, &sc->ebp); - __put_user(regs->esp, &sc->esp); - __put_user(regs->ebx, &sc->ebx); - __put_user(regs->edx, &sc->edx); - __put_user(regs->ecx, &sc->ecx); - __put_user(regs->eax, &sc->eax); - __put_user(current->tss.trap_no, &sc->trapno); - __put_user(current->tss.error_code, &sc->err); - __put_user(regs->eip, &sc->eip); - __put_user(regs->xcs, (unsigned int *)&sc->cs); - __put_user(regs->eflags, &sc->eflags); - __put_user(regs->esp, &sc->esp_at_signal); - __put_user(regs->xss, (unsigned int *)&sc->ss); + err |= __put_user(tmp, (unsigned int *)&sc->fs); - __put_user(save_i387(fpstate), &sc->fpstate); + err |= __put_user(regs->xes, (unsigned int *)&sc->es); + err |= __put_user(regs->xds, (unsigned int *)&sc->ds); + err |= __put_user(regs->edi, &sc->edi); + err |= __put_user(regs->esi, &sc->esi); + err |= __put_user(regs->ebp, &sc->ebp); + err |= __put_user(regs->esp, &sc->esp); + err |= __put_user(regs->ebx, &sc->ebx); + err |= __put_user(regs->edx, &sc->edx); + err |= __put_user(regs->ecx, &sc->ecx); + err |= __put_user(regs->eax, &sc->eax); + err |= __put_user(current->tss.trap_no, &sc->trapno); + err |= __put_user(current->tss.error_code, &sc->err); + err |= __put_user(regs->eip, &sc->eip); + err |= __put_user(regs->xcs, (unsigned int *)&sc->cs); + err |= __put_user(regs->eflags, &sc->eflags); + err |= __put_user(regs->esp, &sc->esp_at_signal); + err |= __put_user(regs->xss, (unsigned int *)&sc->ss); + + tmp = save_i387(fpstate); + if (tmp < 0) + err = 1; + else + err |= __put_user(tmp ? fpstate : NULL, &sc->fpstate); /* non-iBCS2 extensions.. */ - __put_user(mask, &sc->oldmask); - __put_user(current->tss.cr2, &sc->cr2); + err |= __put_user(mask, &sc->oldmask); + err |= __put_user(current->tss.cr2, &sc->cr2); + + return err; } /* * Determine which stack to use.. */ -static inline unsigned long sigstack_esp(struct k_sigaction *ka, struct pt_regs * regs) +static inline void * +get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) { unsigned long esp; /* Default to using normal stack */ esp = regs->esp; + /* This is the X/Open sanctioned signal stack switching. */ + if (ka->sa.sa_flags & SA_ONSTACK) { + if (! on_sig_stack(esp)) + esp = current->sas_ss_sp + current->sas_ss_size; + } + /* This is the legacy signal stack switching. */ - if ((regs->xss & 0xffff) != __USER_DS && - !(ka->sa.sa_flags & SA_RESTORER) && - ka->sa.sa_restorer) + else if ((regs->xss & 0xffff) != __USER_DS && + !(ka->sa.sa_flags & SA_RESTORER) && + ka->sa.sa_restorer) { esp = (unsigned long) ka->sa.sa_restorer; + } - return esp; + return (void *)((esp - frame_size) & -8ul); } static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) { struct sigframe *frame; + int err = 0; - frame = (struct sigframe *)((sigstack_esp(ka, regs) - sizeof(*frame)) & -8); + frame = get_sigframe(ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - goto segv_and_exit; + goto give_sigsegv; - __put_user((current->exec_domain - && current->exec_domain->signal_invmap - && sig < 32 - ? current->exec_domain->signal_invmap[sig] - : sig), - &frame->sig); + err |= __put_user((current->exec_domain + && current->exec_domain->signal_invmap + && sig < 32 + ? current->exec_domain->signal_invmap[sig] + : sig), + &frame->sig); - setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]); + err |= setup_sigcontext(&frame->sc, &frame->fpstate, regs, set->sig[0]); if (_NSIG_WORDS > 1) { - __copy_to_user(frame->extramask, &set->sig[1], - sizeof(frame->extramask)); + err |= __copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); } /* Set up to return from userspace. If provided, use a stub already in userspace. */ if (ka->sa.sa_flags & SA_RESTORER) { - __put_user(ka->sa.sa_restorer, &frame->pretcode); + err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); } else { - __put_user(frame->retcode, &frame->pretcode); + err |= __put_user(frame->retcode, &frame->pretcode); /* This is popl %eax ; movl $,%eax ; int $0x80 */ - __put_user(0xb858, (short *)(frame->retcode+0)); - __put_user(__NR_sigreturn, (int *)(frame->retcode+2)); - __put_user(0x80cd, (short *)(frame->retcode+6)); + err |= __put_user(0xb858, (short *)(frame->retcode+0)); + err |= __put_user(__NR_sigreturn, (int *)(frame->retcode+2)); + err |= __put_user(0x80cd, (short *)(frame->retcode+6)); } + if (err) + goto give_sigsegv; + /* Set up registers for signal handler */ regs->esp = (unsigned long) frame; regs->eip = (unsigned long) ka->sa.sa_handler; @@ -443,50 +484,60 @@ static void setup_frame(int sig, struct return; -segv_and_exit: - lock_kernel(); - do_exit(SIGSEGV); +give_sigsegv: + if (sig == SIGSEGV) + force_sig(SIGSEGV, current); + else + send_sig(SIGSEGV, current, 1); } static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs * regs) { struct rt_sigframe *frame; + int err = 0; - frame = (struct rt_sigframe *)((sigstack_esp(ka, regs) - sizeof(*frame)) & -8); + frame = get_sigframe(ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - goto segv_and_exit; + goto give_sigsegv; - __put_user((current->exec_domain - && current->exec_domain->signal_invmap - && sig < 32 - ? current->exec_domain->signal_invmap[sig] - : sig), - &frame->sig); - __put_user(&frame->info, &frame->pinfo); - __put_user(&frame->uc, &frame->puc); - __copy_to_user(&frame->info, info, sizeof(*info)); - - /* Clear all the bits of the ucontext we don't use. */ - __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); - - setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, - regs, set->sig[0]); - __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + err |= __put_user((current->exec_domain + && current->exec_domain->signal_invmap + && sig < 32 + ? current->exec_domain->signal_invmap[sig] + : sig), + &frame->sig); + err |= __put_user(&frame->info, &frame->pinfo); + err |= __put_user(&frame->uc, &frame->puc); + err |= __copy_to_user(&frame->info, info, sizeof(*info)); + + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(regs->esp), + &frame->uc.uc_stack.ss_flags); + err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate, + regs, set->sig[0]); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); /* Set up to return from userspace. If provided, use a stub already in userspace. */ if (ka->sa.sa_flags & SA_RESTORER) { - __put_user(ka->sa.sa_restorer, &frame->pretcode); + err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); } else { - __put_user(frame->retcode, &frame->pretcode); + err |= __put_user(frame->retcode, &frame->pretcode); /* This is movl $,%eax ; int $0x80 */ - __put_user(0xb8, (char *)(frame->retcode+0)); - __put_user(__NR_rt_sigreturn, (int *)(frame->retcode+1)); - __put_user(0x80cd, (short *)(frame->retcode+5)); + err |= __put_user(0xb8, (char *)(frame->retcode+0)); + err |= __put_user(__NR_rt_sigreturn, (int *)(frame->retcode+1)); + err |= __put_user(0x80cd, (short *)(frame->retcode+5)); } + if (err) + goto give_sigsegv; + /* Set up registers for signal handler */ regs->esp = (unsigned long) frame; regs->eip = (unsigned long) ka->sa.sa_handler; @@ -508,9 +559,11 @@ static void setup_rt_frame(int sig, stru return; -segv_and_exit: - lock_kernel(); - do_exit(SIGSEGV); +give_sigsegv: + if (sig == SIGSEGV) + force_sig(SIGSEGV, current); + else + send_sig(SIGSEGV, current, 1); } /* diff -rup 2.1.105/arch/i386/math-emu/fpu_entry.c 2.1.105-rth/arch/i386/math-emu/fpu_entry.c --- 2.1.105/arch/i386/math-emu/fpu_entry.c Thu Feb 5 14:39:41 1998 +++ 2.1.105-rth/arch/i386/math-emu/fpu_entry.c Sun Jun 7 21:53:50 1998 @@ -677,14 +677,15 @@ void math_abort(struct info * info, unsi #define sstatus_word() \ ((S387->swd & ~SW_Top & 0xffff) | ((S387->ftop << SW_Top_Shift) & SW_Top)) -void restore_i387_soft(void *s387, struct _fpstate *buf) +int restore_i387_soft(void *s387, struct _fpstate *buf) { u_char *d = (u_char *)buf; int offset, other, i, tags, regnr, tag, newtop; RE_ENTRANT_CHECK_OFF; FPU_verify_area(VERIFY_READ, d, 7*4 + 8*10); - __copy_from_user(&S387->cwd, d, 7*4); + if (__copy_from_user(&S387->cwd, d, 7*4)) + return -1; RE_ENTRANT_CHECK_ON; d += 7*4; @@ -695,9 +696,11 @@ void restore_i387_soft(void *s387, struc RE_ENTRANT_CHECK_OFF; /* Copy all registers in stack order. */ - __copy_from_user(((u_char *)&S387->st_space)+offset, d, other); + if (__copy_from_user(((u_char *)&S387->st_space)+offset, d, other)) + return -1; if ( offset ) - __copy_from_user((u_char *)&S387->st_space, d+other, offset); + if (__copy_from_user((u_char *)&S387->st_space, d+other, offset)) + return -1; RE_ENTRANT_CHECK_ON; /* The tags may need to be corrected now. */ @@ -716,10 +719,11 @@ void restore_i387_soft(void *s387, struc } S387->twd = tags; + return 0; } -struct _fpstate * save_i387_soft(void *s387, struct _fpstate * buf) +int save_i387_soft(void *s387, struct _fpstate * buf) { u_char *d = (u_char *)buf; int offset = (S387->ftop & 7) * 10, other = 80 - offset; @@ -742,10 +746,12 @@ struct _fpstate * save_i387_soft(void *s RE_ENTRANT_CHECK_OFF; /* Copy all registers in stack order. */ - __copy_to_user(d, ((u_char *)&S387->st_space)+offset, other); + if (__copy_to_user(d, ((u_char *)&S387->st_space)+offset, other)) + return -1; if ( offset ) - __copy_to_user(d+other, (u_char *)&S387->st_space, offset); + if (__copy_to_user(d+other, (u_char *)&S387->st_space, offset)) + return -1 RE_ENTRANT_CHECK_ON; - return buf; + return 1; } diff -rup 2.1.105/include/asm-alpha/signal.h 2.1.105-rth/include/asm-alpha/signal.h --- 2.1.105/include/asm-alpha/signal.h Sat Feb 28 17:04:01 1998 +++ 2.1.105-rth/include/asm-alpha/signal.h Sun Jun 7 22:33:32 1998 @@ -76,7 +76,7 @@ typedef unsigned long sigset_t; /* * SA_FLAGS values: * - * SA_ONSTACK is not currently supported, but will allow sigaltstack(2). + * SA_ONSTACK indicates that a registered stack_t will be used. * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the * SA_RESTART flag to get restarting signals (which were the default long ago) * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. @@ -100,6 +100,16 @@ typedef unsigned long sigset_t; #define SA_NOMASK SA_NODEFER #define SA_INTERRUPT 0x20000000 /* dummy -- ignored */ +/* + * sigaltstack controls + */ +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +#define MINSIGSTKSZ 4096 +#define SIGSTKSZ 16384 + + #ifdef __KERNEL__ /* * These values of sa_flags are used only by the kernel as part of the @@ -163,6 +173,15 @@ typedef struct sigaltstack { int ss_flags; size_t ss_size; } stack_t; + +/* sigstack(2) is deprecated, and will be withdrawn in a future version + of the X/Open CAE Specification. Use sigaltstack instead. It is only + implemented here for OSF/1 compatability. */ + +struct sigstack { + void *ss_sp; + int ss_onstack; +}; #ifdef __KERNEL__ #include <asm/sigcontext.h> diff -rup 2.1.105/include/asm-alpha/unistd.h 2.1.105-rth/include/asm-alpha/unistd.h --- 2.1.105/include/asm-alpha/unistd.h Mon Jun 8 00:30:04 1998 +++ 2.1.105-rth/include/asm-alpha/unistd.h Sun Jun 7 22:33:33 1998 @@ -113,7 +113,7 @@ #define __NR_osf_old_sigblock 109 /* not implemented */ #define __NR_osf_old_sigsetmask 110 /* not implemented */ #define __NR_sigsuspend 111 -#define __NR_osf_sigstack 112 /* not implemented */ +#define __NR_osf_sigstack 112 #define __NR_recvmsg 113 #define __NR_sendmsg 114 #define __NR_osf_old_vtrace 115 /* not implemented */ @@ -205,7 +205,7 @@ #define __NR_getpgid 233 #define __NR_getsid 234 -#define __NR_osf_sigaltstack 235 /* not implemented */ +#define __NR_sigaltstack 235 #define __NR_osf_waitid 236 /* not implemented */ #define __NR_osf_priocntlset 237 /* not implemented */ #define __NR_osf_sigsendset 238 /* not implemented */ diff -rup 2.1.105/include/asm-i386/math_emu.h 2.1.105-rth/include/asm-i386/math_emu.h --- 2.1.105/include/asm-i386/math_emu.h Sun Dec 21 03:46:06 1997 +++ 2.1.105-rth/include/asm-i386/math_emu.h Sun Jun 7 21:53:50 1998 @@ -3,8 +3,8 @@ #include <asm/sigcontext.h> -void restore_i387_soft(void *s387, struct _fpstate *buf); -struct _fpstate * save_i387_soft(void *s387, struct _fpstate * buf); +int restore_i387_soft(void *s387, struct _fpstate *buf); +int save_i387_soft(void *s387, struct _fpstate * buf); /* This structure matches the layout of the data saved to the stack following a device-not-present interrupt, part of it saved diff -rup 2.1.105/include/asm-i386/signal.h 2.1.105-rth/include/asm-i386/signal.h --- 2.1.105/include/asm-i386/signal.h Sat Feb 28 17:04:01 1998 +++ 2.1.105-rth/include/asm-i386/signal.h Sun Jun 7 21:53:50 1998 @@ -72,7 +72,7 @@ typedef unsigned long sigset_t; /* * SA_FLAGS values: * - * SA_ONSTACK is not currently supported, but will allow sigaltstack(2). + * SA_ONSTACK indicates that a registered stack_t will be used. * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the * SA_RESTART flag to get restarting signals (which were the default long ago) * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. @@ -96,6 +96,15 @@ typedef unsigned long sigset_t; #define SA_INTERRUPT 0x20000000 /* dummy -- ignored */ #define SA_RESTORER 0x04000000 + +/* + * sigaltstack controls + */ +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 #ifdef __KERNEL__ diff -rup 2.1.105/include/asm-i386/unistd.h 2.1.105-rth/include/asm-i386/unistd.h --- 2.1.105/include/asm-i386/unistd.h Thu Jun 4 23:43:30 1998 +++ 2.1.105-rth/include/asm-i386/unistd.h Sun Jun 7 21:53:50 1998 @@ -191,6 +191,7 @@ #define __NR_getcwd 183 #define __NR_capget 184 #define __NR_capset 185 +#define __NR_sigaltstack 186 /* user-visible error numbers are in the range -1 - -122: see <asm-i386/errno.h> */ Only in 2.1.105/include/linux: modules diff -rup 2.1.105/include/linux/sched.h 2.1.105-rth/include/linux/sched.h --- 2.1.105/include/linux/sched.h Mon Jun 8 00:30:05 1998 +++ 2.1.105-rth/include/linux/sched.h Sun Jun 7 23:01:31 1998 @@ -284,6 +284,8 @@ struct task_struct { struct signal_struct *sig; sigset_t signal, blocked; struct signal_queue *sigqueue, **sigqueue_tail; + unsigned long sas_ss_sp; + size_t sas_ss_size; /* SMP state */ int has_cpu; int processor; @@ -365,6 +367,7 @@ struct task_struct { /* files */ &init_files, \ /* mm */ &init_mm, \ /* signals */ &init_signals, {{0}}, {{0}}, NULL, &init_task.sigqueue, \ + 0, 0, \ /* SMP */ 0,0,0,0, \ /* locks */ INIT_LOCKS \ } @@ -480,6 +483,7 @@ extern int kill_sl(pid_t, int, int); extern int kill_proc(pid_t, int, int); extern int do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact); +extern int do_sigaltstack(stack_t *ss, stack_t *oss, unsigned long sp); extern inline int signal_pending(struct task_struct *p) { @@ -517,6 +521,19 @@ static inline void recalc_sigpending(str t->sigpending = (ready != 0); } +/* True if we are on the alternate signal stack. */ + +static inline int on_sig_stack(unsigned long sp) +{ + return (sp >= current->sas_ss_sp + && sp < current->sas_ss_sp + current->sas_ss_size); +} + +static inline int sas_ss_flags(unsigned long sp) +{ + return (current->sas_ss_size == 0 ? SS_DISABLE + : on_sig_stack(sp) ? SS_ONSTACK : 0); +} extern int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), diff -rup 2.1.105/kernel/signal.c 2.1.105-rth/kernel/signal.c --- 2.1.105/kernel/signal.c Thu Jun 4 23:43:33 1998 +++ 2.1.105-rth/kernel/signal.c Mon Jun 8 10:38:51 1998 @@ -840,6 +840,62 @@ do_sigaction(int sig, const struct k_sig return 0; } +int +do_sigaltstack (stack_t *uss, stack_t *uoss, unsigned long sp) +{ + stack_t oss; + int error; + + if (uoss) { + oss.ss_sp = (void *) current->sas_ss_sp; + oss.ss_size = current->sas_ss_size; + oss.ss_flags = sas_ss_flags(sp); + } + + if (uss) { + void *ss_sp; + size_t ss_size; + int ss_flags; + + error = -EFAULT; + if (verify_area(VERIFY_READ, uss, sizeof(*uss)) + || __get_user(ss_sp, &uss->ss_sp) + || __get_user(ss_flags, &uss->ss_flags) + || __get_user(ss_size, &uss->ss_size)) + goto out; + + error = -EPERM; + if (on_sig_stack (sp)) + goto out; + + error = -EINVAL; + if (ss_flags & ~SS_DISABLE) + goto out; + + if (ss_flags & SS_DISABLE) { + ss_size = 0; + ss_sp = NULL; + } else { + error = -ENOMEM; + if (ss_size < MINSIGSTKSZ) + goto out; + } + + current->sas_ss_sp = (unsigned long) ss_sp; + current->sas_ss_size = ss_size; + } + + if (uoss) { + error = -EFAULT; + if (copy_to_user(uoss, &oss, sizeof(oss))) + goto out; + } + + error = 0; +out: + return error; +} + #if !defined(__alpha__) /* Alpha has its own versions with special arguments. */ - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu
| |