[PATCH] ppc32: Kill init on unhandled synchronous signals
authorPaul Mackerras <paulus@samba.org>
Sat, 10 Sep 2005 11:13:11 +0000 (21:13 +1000)
committerLinus Torvalds <torvalds@g5.osdl.org>
Sat, 10 Sep 2005 17:15:11 +0000 (10:15 -0700)
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>
arch/ppc/kernel/traps.c
arch/ppc/mm/fault.c
include/asm-ppc/system.h

index 8356d544fa60dc3cbda579cc43c075637bddbaf3..961ede87be72254f421d6f2f269668bb19f54070 100644 (file)
@@ -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);
+               }
+       }
 }
 
 /*
index 57d9930843ac28f9d5c726071c8368fc8a69942b..ee5e9f25baf98d7c567361739ee30864bb8c980d 100644 (file)
@@ -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;
        }
 
index 513a334c581032ec21ddc33819d7e25dad5b4bd0..d754ab570fe0eba855c55e53446564076f6d895f 100644 (file)
@@ -88,6 +88,7 @@ extern void *cacheable_memcpy(void *, const void *, unsigned int);
 extern int do_page_fault(struct pt_regs *, unsigned long, unsigned long);
 extern void bad_page_fault(struct pt_regs *, unsigned long, int);
 extern void die(const char *, struct pt_regs *, long);
+extern void _exception(int, struct pt_regs *, int, unsigned long);
 #ifdef CONFIG_BOOKE_WDT
 extern u32 booke_wdt_enabled;
 extern u32 booke_wdt_period;