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

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