X-Yow: What PROGRAM are they watching?
To: linux-m68k@lists.linux-m68k.org
Subject: L68K: Signal handling bugs
From: Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
Date: 17 Aug 1998 12:01:36 +0200
Sender: owner-linux-m68k@phil.uni-sb.de

This patch fixes two problems with the signal handling.  The first one is
in the m68k specific handling: when the setup of the signal context failed
(perhaps due to stack overflow) then regs->stkadj may be set without the
new exception frame is being created, so that the RTE will use random bits
causing a format error exception or other nasty things in kernel context.
The change in force_sig_info is needed because the signal to be sent may
already be pending but blocked, and we would unblock it without setting
t->sigpending.

Andreas.

----------------------------------------------------------------------
--- linux-2.1/arch/m68k/kernel/signal.c.~1~	Tue Jun 16 09:42:12 1998
+++ linux-2.1/arch/m68k/kernel/signal.c	Sun Aug 16 10:59:07 1998
@@ -808,16 +808,11 @@
 
 	push_cache ((unsigned long) &frame->retcode);
 
-	/*
-	 * no matter what frame format we were using before, we
-	 * will do the "RTE" using a normal 4 word frame.
-	 */
-	regs->format = 0;
-
 	/* Set up registers for signal handler */
 	wrusp ((unsigned long) frame);
 	regs->pc = (unsigned long) ka->sa.sa_handler;
 
+adjust_stack:
 	/* Prepare to skip over the extra stuff in the exception frame.  */
 	if (regs->stkadj) {
 		struct pt_regs *tregs =
@@ -827,8 +822,8 @@
 #endif
 		/* This must be copied with decreasing addresses to
                    handle overlaps.  */
-		tregs->vector = regs->vector;
-		tregs->format = regs->format;
+		tregs->vector = 0;
+		tregs->format = 0;
 		tregs->pc = regs->pc;
 		tregs->sr = regs->sr;
 	}
@@ -838,6 +833,7 @@
 	if (sig == SIGSEGV)
 		ka->sa.sa_handler = SIG_DFL;
 	force_sig(SIGSEGV, current);
+	goto adjust_stack;
 }
 
 static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -895,16 +891,11 @@
 
 	push_cache ((unsigned long) &frame->retcode);
 
-	/*
-	 * no matter what frame format we were using before, we
-	 * will do the "RTE" using a normal 4 word frame.
-	 */
-	regs->format = 0;
-
 	/* Set up registers for signal handler */
 	wrusp ((unsigned long) frame);
 	regs->pc = (unsigned long) ka->sa.sa_handler;
 
+adjust_stack:
 	/* Prepare to skip over the extra stuff in the exception frame.  */
 	if (regs->stkadj) {
 		struct pt_regs *tregs =
@@ -914,8 +905,8 @@
 #endif
 		/* This must be copied with decreasing addresses to
                    handle overlaps.  */
-		tregs->vector = regs->vector;
-		tregs->format = regs->format;
+		tregs->vector = 0;
+		tregs->format = 0;
 		tregs->pc = regs->pc;
 		tregs->sr = regs->sr;
 	}
@@ -925,6 +916,7 @@
 	if (sig == SIGSEGV)
 		ka->sa.sa_handler = SIG_DFL;
 	force_sig(SIGSEGV, current);
+	goto adjust_stack;
 }
 
 static inline void
@@ -970,7 +962,7 @@
 		setup_frame(sig, ka, oldset, regs);
 
 	if (ka->sa.sa_flags & SA_ONESHOT)
-		ka->sa.sa_handler = NULL;
+		ka->sa.sa_handler = SIG_DFL;
 
 	if (!(ka->sa.sa_flags & SA_NODEFER)) {
 		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
@@ -1030,10 +1022,8 @@
 			discard_frame:
 			    /* Make sure that a faulted bus cycle isn't
 			       restarted (only needed on the 680[23]0).  */
-			    if (regs->format == 10 || regs->format == 11) {
+			    if (regs->format == 10 || regs->format == 11)
 				regs->stkadj = frame_extra_sizes[regs->format];
-				regs->format = 0;
-			    }
 			    continue;
 			}
 			current->exit_code = 0;
@@ -1126,8 +1116,8 @@
 
 		/* This must be copied with decreasing addresses to
 		   handle overlaps.  */
-		tregs->vector = regs->vector;
-		tregs->format = regs->format;
+		tregs->vector = 0;
+		tregs->format = 0;
 		tregs->pc = regs->pc;
 		tregs->sr = regs->sr;
 	}
--- linux-2.1/kernel/signal.c.~1~	Mon Jul 13 18:54:08 1998
+++ linux-2.1/kernel/signal.c	Sun Aug 16 13:00:24 1998
@@ -368,6 +368,7 @@
 	if (t->sig->action[sig-1].sa.sa_handler == SIG_IGN)
 		t->sig->action[sig-1].sa.sa_handler = SIG_DFL;
 	sigdelset(&t->blocked, sig);
+	recalc_sigpending(t);
 
 	return send_sig_info(sig, info, t);
 }
