summary refs log tree commit diff
path: root/arch
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2005-09-10 21:13:11 +1000
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-10 10:15:11 -0700
commitbb0bb3b6596cdb08adb0b72453cc67d48e139c2c (patch)
treef9116ed650d499d405a3fe021c473f9558897d96 /arch
parent1e63bc7342c40f0f1dd83d80d368665bd06f4963 (diff)
downloadlinux-bb0bb3b6596cdb08adb0b72453cc67d48e139c2c.tar.gz
[PATCH] ppc32: Kill init on unhandled synchronous signals
This is a patch that I have had in my tree for ages.  If init causes
an exception that raises a signal, such as a SIGSEGV, SIGILL or
SIGFPE, and it hasn't registered a handler for it, we don't deliver
the signal, since init doesn't get any signals that it doesn't have a
handler for.  But that means that we just return to userland and
generate the same exception again immediately.  With this patch we
print a message and kill init in this situation.

This is very useful when you have a bug in the kernel that means that
init doesn't get as far as executing its first instruction. :)
Without this patch the system hangs when it gets to starting the
userland init; with it you at least get a message giving you a clue
about what has gone wrong.

Signed-off-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/ppc/kernel/traps.c22
-rw-r--r--arch/ppc/mm/fault.c6
2 files changed, 23 insertions, 5 deletions
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index 8356d544fa60..961ede87be72 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -118,6 +118,28 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
 	info.si_code = code;
 	info.si_addr = (void __user *) addr;
 	force_sig_info(signr, &info, current);
+
+	/*
+	 * Init gets no signals that it doesn't have a handler for.
+	 * That's all very well, but if it has caused a synchronous
+	 * exception and we ignore the resulting signal, it will just
+	 * generate the same exception over and over again and we get
+	 * nowhere.  Better to kill it and let the kernel panic.
+	 */
+	if (current->pid == 1) {
+		__sighandler_t handler;
+
+		spin_lock_irq(&current->sighand->siglock);
+		handler = current->sighand->action[signr-1].sa.sa_handler;
+		spin_unlock_irq(&current->sighand->siglock);
+		if (handler == SIG_DFL) {
+			/* init has generated a synchronous exception
+			   and it doesn't have a handler for the signal */
+			printk(KERN_CRIT "init has generated signal %d "
+			       "but has no handler for it\n", signr);
+			do_exit(signr);
+		}
+	}
 }
 
 /*
diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c
index 57d9930843ac..ee5e9f25baf9 100644
--- a/arch/ppc/mm/fault.c
+++ b/arch/ppc/mm/fault.c
@@ -278,11 +278,7 @@ bad_area:
 
 	/* User mode accesses cause a SIGSEGV */
 	if (user_mode(regs)) {
-		info.si_signo = SIGSEGV;
-		info.si_errno = 0;
-		info.si_code = code;
-		info.si_addr = (void __user *) address;
-		force_sig_info(SIGSEGV, &info, current);
+		_exception(SIGSEGV, regs, code, address);
 		return 0;
 	}