diff options
| author | Paul Mackerras <paulus@samba.org> | 2005-09-10 07:13:11 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-10 13:15:11 -0400 |
| commit | bb0bb3b6596cdb08adb0b72453cc67d48e139c2c (patch) | |
| tree | f9116ed650d499d405a3fe021c473f9558897d96 | |
| parent | 1e63bc7342c40f0f1dd83d80d368665bd06f4963 (diff) | |
[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>
| -rw-r--r-- | arch/ppc/kernel/traps.c | 22 | ||||
| -rw-r--r-- | arch/ppc/mm/fault.c | 6 | ||||
| -rw-r--r-- | include/asm-ppc/system.h | 1 |
3 files changed, 24 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) | |||
| 118 | info.si_code = code; | 118 | info.si_code = code; |
| 119 | info.si_addr = (void __user *) addr; | 119 | info.si_addr = (void __user *) addr; |
| 120 | force_sig_info(signr, &info, current); | 120 | force_sig_info(signr, &info, current); |
| 121 | |||
| 122 | /* | ||
| 123 | * Init gets no signals that it doesn't have a handler for. | ||
| 124 | * That's all very well, but if it has caused a synchronous | ||
| 125 | * exception and we ignore the resulting signal, it will just | ||
| 126 | * generate the same exception over and over again and we get | ||
| 127 | * nowhere. Better to kill it and let the kernel panic. | ||
| 128 | */ | ||
| 129 | if (current->pid == 1) { | ||
| 130 | __sighandler_t handler; | ||
| 131 | |||
| 132 | spin_lock_irq(¤t->sighand->siglock); | ||
| 133 | handler = current->sighand->action[signr-1].sa.sa_handler; | ||
| 134 | spin_unlock_irq(¤t->sighand->siglock); | ||
| 135 | if (handler == SIG_DFL) { | ||
| 136 | /* init has generated a synchronous exception | ||
| 137 | and it doesn't have a handler for the signal */ | ||
| 138 | printk(KERN_CRIT "init has generated signal %d " | ||
| 139 | "but has no handler for it\n", signr); | ||
| 140 | do_exit(signr); | ||
| 141 | } | ||
| 142 | } | ||
| 121 | } | 143 | } |
| 122 | 144 | ||
| 123 | /* | 145 | /* |
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: | |||
| 278 | 278 | ||
| 279 | /* User mode accesses cause a SIGSEGV */ | 279 | /* User mode accesses cause a SIGSEGV */ |
| 280 | if (user_mode(regs)) { | 280 | if (user_mode(regs)) { |
| 281 | info.si_signo = SIGSEGV; | 281 | _exception(SIGSEGV, regs, code, address); |
| 282 | info.si_errno = 0; | ||
| 283 | info.si_code = code; | ||
| 284 | info.si_addr = (void __user *) address; | ||
| 285 | force_sig_info(SIGSEGV, &info, current); | ||
| 286 | return 0; | 282 | return 0; |
| 287 | } | 283 | } |
| 288 | 284 | ||
diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h index 513a334c5810..d754ab570fe0 100644 --- a/include/asm-ppc/system.h +++ b/include/asm-ppc/system.h | |||
| @@ -88,6 +88,7 @@ extern void *cacheable_memcpy(void *, const void *, unsigned int); | |||
| 88 | extern int do_page_fault(struct pt_regs *, unsigned long, unsigned long); | 88 | extern int do_page_fault(struct pt_regs *, unsigned long, unsigned long); |
| 89 | extern void bad_page_fault(struct pt_regs *, unsigned long, int); | 89 | extern void bad_page_fault(struct pt_regs *, unsigned long, int); |
| 90 | extern void die(const char *, struct pt_regs *, long); | 90 | extern void die(const char *, struct pt_regs *, long); |
| 91 | extern void _exception(int, struct pt_regs *, int, unsigned long); | ||
| 91 | #ifdef CONFIG_BOOKE_WDT | 92 | #ifdef CONFIG_BOOKE_WDT |
| 92 | extern u32 booke_wdt_enabled; | 93 | extern u32 booke_wdt_enabled; |
| 93 | extern u32 booke_wdt_period; | 94 | extern u32 booke_wdt_period; |
