patch-2.1.16 linux/arch/ppc/kernel/signal.c
Next file: linux/arch/ppc/kernel/stubs.c
Previous file: linux/arch/ppc/kernel/setup.c
Back to the patch index
Back to the overall index
- Lines: 344
- Date:
Wed Dec 18 10:49:52 1996
- Orig file:
v2.1.15/linux/arch/ppc/kernel/signal.c
- Orig date:
Mon Jul 8 11:27:43 1996
diff -u --recursive --new-file v2.1.15/linux/arch/ppc/kernel/signal.c linux/arch/ppc/kernel/signal.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Adapted for PowerPC by Gary Thomas
+ * Modified by Cort Dougan (cort@cs.nmt.edu)
*/
#include <linux/sched.h>
@@ -13,6 +14,7 @@
#include <linux/wait.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
+#include <asm/uaccess.h>
#define _S(nr) (1<<((nr)-1))
@@ -41,14 +43,16 @@
}
}
-/*
- * This sets regs->esp even though we don't actually use sigstacks yet..
- */
asmlinkage int sys_sigreturn(struct pt_regs *regs)
{
struct sigcontext_struct *sc;
struct pt_regs *int_regs;
int signo;
+#if 1
+ if (verify_area(VERIFY_READ, (void *) regs->gpr[1], sizeof(sc))
+ || (regs->gpr[1] >=KERNELBASE))
+ goto badframe;
+#endif
sc = (struct sigcontext_struct *)regs->gpr[1];
current->blocked = sc->oldmask & _BLOCKABLE;
int_regs = sc->regs;
@@ -82,6 +86,10 @@
regs->nip = sc->handler;
return (sc->signal);
}
+badframe:
+ /*printk("sys_sigreturn(): badstack regs %x cur %s/%d\n",
+ regs,current->comm,current->pid);*/
+ do_exit(SIGSEGV);
}
@@ -96,144 +104,159 @@
*/
asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
{
- unsigned long mask = ~current->blocked;
- unsigned long handler_signal = 0;
- unsigned long *frame = NULL;
- unsigned long *trampoline;
- unsigned long *regs_ptr;
- unsigned long nip = 0;
- unsigned long signr;
- int bitno;
- struct sigcontext_struct *sc;
- struct sigaction * sa;
- int s = _disable_interrupts();
- while ((signr = current->signal & mask)) {
-#if 0
- signr = ffz(~signr); /* Compute bit # */
-#else
- for (bitno = 0; bitno < 32; bitno++)
- {
- if (signr & (1<<bitno)) break;
- }
- signr = bitno;
-#endif
- current->signal &= ~(1<<signr); /* Clear bit */
- sa = current->sig->action + signr;
- signr++;
- if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
- current->exit_code = signr;
- current->state = TASK_STOPPED;
- notify_parent(current);
- schedule();
- if (!(signr = current->exit_code))
- continue;
- current->exit_code = 0;
- if (signr == SIGSTOP)
- continue;
- if (_S(signr) & current->blocked) {
- current->signal |= _S(signr);
- continue;
- }
- sa = current->sig->action + signr - 1;
- }
- if (sa->sa_handler == SIG_IGN) {
- if (signr != SIGCHLD)
- continue;
- /* check for SIGCHLD: it's special */
- while (sys_waitpid(-1,NULL,WNOHANG) > 0)
- /* nothing */;
- continue;
- }
- if (sa->sa_handler == SIG_DFL) {
- if (current->pid == 1)
- continue;
- switch (signr) {
- case SIGCONT: case SIGCHLD: case SIGWINCH:
- continue;
-
- case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
- if (current->flags & PF_PTRACED)
- continue;
- current->state = TASK_STOPPED;
- current->exit_code = signr;
- if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
- SA_NOCLDSTOP))
- notify_parent(current);
- schedule();
- continue;
-
- case SIGQUIT: case SIGILL: case SIGTRAP:
- case SIGIOT: case SIGFPE: case SIGSEGV:
- if (current->binfmt && current->binfmt->core_dump) {
- if (current->binfmt->core_dump(signr, regs))
- signr |= 0x80;
- }
- /* fall through */
- default:
- current->signal |= _S(signr & 0x7f);
- do_exit(signr);
- }
- }
- /*
- * OK, we're invoking a handler
- */
- if ((int)regs->orig_gpr3 >= 0) {
- if ((int)regs->result == -ERESTARTNOHAND ||
- ((int)regs->result == -ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
- (int)regs->result = -EINTR;
- }
- handler_signal |= 1 << (signr-1);
- mask &= ~sa->sa_mask;
+ unsigned long mask = ~current->blocked;
+ unsigned long handler_signal = 0;
+ unsigned long *frame = NULL;
+ unsigned long *trampoline;
+ unsigned long *regs_ptr;
+ unsigned long nip = 0;
+ unsigned long signr;
+ int bitno;
+ struct sigcontext_struct *sc;
+ struct sigaction * sa;
+ int s;
+
+ while ((signr = current->signal & mask)) {
+ for (bitno = 0; bitno < 32; bitno++)
+ {
+ if (signr & (1<<bitno)) break;
+ }
+ signr = bitno;
+
+ current->signal &= ~(1<<signr); /* Clear bit */
+ sa = current->sig->action + signr;
+ signr++;
+ if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
+ current->exit_code = signr;
+ current->state = TASK_STOPPED;
+ notify_parent(current);
+ schedule();
+ if (!(signr = current->exit_code))
+ continue;
+ current->exit_code = 0;
+ if (signr == SIGSTOP)
+ continue;
+ if (_S(signr) & current->blocked) {
+ current->signal |= _S(signr);
+ continue;
+ }
+ sa = current->sig->action + signr - 1;
+ }
+ if (sa->sa_handler == SIG_IGN) {
+ if (signr != SIGCHLD)
+ continue;
+ /* check for SIGCHLD: it's special */
+ while (sys_waitpid(-1,NULL,WNOHANG) > 0)
+ /* nothing */;
+ continue;
+ }
+ if (sa->sa_handler == SIG_DFL) {
+ if (current->pid == 1)
+ continue;
+ switch (signr) {
+ case SIGCONT: case SIGCHLD: case SIGWINCH:
+ continue;
+
+ case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
+ if (current->flags & PF_PTRACED)
+ continue;
+ current->state = TASK_STOPPED;
+ current->exit_code = signr;
+ if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
+ SA_NOCLDSTOP))
+ notify_parent(current);
+ schedule();
+ continue;
+
+ case SIGQUIT: case SIGILL: case SIGTRAP:
+ case SIGIOT: case SIGFPE: case SIGSEGV:
+ if (current->binfmt && current->binfmt->core_dump) {
+ if (current->binfmt->core_dump(signr, regs))
+ signr |= 0x80;
}
- if (!handler_signal) /* no handler will be called - return 0 */
- {
- _enable_interrupts(s);
- return 0;
- }
- nip = regs->nip;
- frame = (unsigned long *) regs->gpr[1];
- /* Build trampoline code on stack */
- frame -= 2;
- trampoline = frame;
- trampoline[0] = 0x38007777; /* li r0,0x7777 */
- trampoline[1] = 0x44000002; /* sc */
- frame -= sizeof(*regs) / sizeof(long);
- regs_ptr = frame;
- memcpy(regs_ptr, regs, sizeof(*regs));
- signr = 1;
- sa = current->sig->action;
- for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
- if (mask > handler_signal)
- break;
- if (!(mask & handler_signal))
- continue;
- frame -= sizeof(struct sigcontext_struct) / sizeof(long);
- sc = (struct sigcontext_struct *)frame;
- nip = (unsigned long) sa->sa_handler;
+ /* fall through */
+ default:
+ current->signal |= _S(signr & 0x7f);
+ do_exit(signr);
+ }
+ }
+ /* handle signal */
+
+ if ((int)regs->orig_gpr3 >= 0) {
+ if ((int)regs->result == -ERESTARTNOHAND ||
+ ((int)regs->result == -ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))
+ (int)regs->result = -EINTR;
+ }
+ handler_signal |= 1 << (signr-1);
+ mask &= ~sa->sa_mask;
+ }
+ if (!handler_signal) /* no handler will be called - return 0 */
+ {
+ return 0;
+ }
+
+
+ nip = regs->nip;
+ frame = (unsigned long *) regs->gpr[1];
+ /* Build trampoline code on stack */
+ frame -= 2;
+ trampoline = frame;
+#if 1
+ /* verify stack is valid for writing regs struct */
+ if (verify_area(VERIFY_WRITE,(void *)frame, sizeof(long)*2+sizeof(*regs))
+ || (frame >= KERNELBASE ))
+ goto badframe;
+#endif
+ trampoline[0] = 0x38007777; /* li r0,0x7777 */
+ trampoline[1] = 0x44000002; /* sc */
+ frame -= sizeof(*regs) / sizeof(long);
+ regs_ptr = frame;
+ memcpy(regs_ptr, regs, sizeof(*regs));
+ signr = 1;
+ sa = current->sig->action;
+
+
+ for (mask = 1 ; mask ; sa++,signr++,mask += mask) {
+ if (mask > handler_signal)
+ break;
+ if (!(mask & handler_signal))
+ continue;
+
+ frame -= sizeof(struct sigcontext_struct) / sizeof(long);
+#if 1
+ if (verify_area(VERIFY_WRITE,(void *)frame,
+ sizeof(struct sigcontext_struct)/sizeof(long)))
+ goto badframe;
+#endif
+ sc = (struct sigcontext_struct *)frame;
+ nip = (unsigned long) sa->sa_handler;
#if 0 /* Old compiler */
- nip = *(unsigned long *)nip;
+ nip = *(unsigned long *)nip;
#endif
- if (sa->sa_flags & SA_ONESHOT)
- sa->sa_handler = NULL;
- sc->handler = nip;
- sc->oldmask = current->blocked;
- sc->regs = (unsigned long)regs_ptr;
- sc->signal = signr;
- current->blocked |= sa->sa_mask;
- regs->gpr[3] = signr;
- regs->gpr[4] = (unsigned long)regs_ptr;
- }
- regs->link = (unsigned long)trampoline;
- regs->nip = nip;
- regs->gpr[1] = (unsigned long)sc;
- /* The DATA cache must be flushed here to insure coherency */
- /* between the DATA & INSTRUCTION caches. Since we just */
- /* created an instruction stream using the DATA [cache] space */
- /* and since the instruction cache will not look in the DATA */
- /* cache for new data, we have to force the data to go on to */
- /* memory and flush the instruction cache to force it to look */
- /* there. The following function performs this magic */
- flush_instruction_cache();
- _enable_interrupts(s);
- return 1;
+ if (sa->sa_flags & SA_ONESHOT)
+ sa->sa_handler = NULL;
+ sc->handler = nip;
+ sc->oldmask = current->blocked;
+ sc->regs = (unsigned long)regs_ptr;
+ sc->signal = signr;
+ current->blocked |= sa->sa_mask;
+ regs->gpr[3] = signr;
+ regs->gpr[4] = (unsigned long)regs_ptr;
+ }
+ regs->link = (unsigned long)trampoline;
+ regs->nip = nip;
+ regs->gpr[1] = (unsigned long)sc;
+ /* The DATA cache must be flushed here to insure coherency */
+ /* between the DATA & INSTRUCTION caches. Since we just */
+ /* created an instruction stream using the DATA [cache] space */
+ /* and since the instruction cache will not look in the DATA */
+ /* cache for new data, we have to force the data to go on to */
+ /* memory and flush the instruction cache to force it to look */
+ /* there. The following function performs this magic */
+ flush_instruction_cache();
+ return 1;
+badframe:
+ /* printk("do_signal(): badstack signr %d frame %x regs %x cur %s/%d\n",
+ signr,frame,regs,current->comm,current->pid);*/
+ do_exit(SIGSEGV);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov