Skip to contentSkip to conversation

If init dies, log a signal which killed it, if any.

PATCH Superseded Denys Vlasenko 2 participants 2 messages Jan 20, 2012

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 If init dies, log a signal which killed it, if any.

I just received another user's pleas for help when their init mystriously dies. I again explained that they need to check whether it dies because of bad instruction, a segv, or something else.

Which prompted me to make kernel do this first step automatically. We can easily detect when the death is from e.g. SIGILL, and let user know that.

The code is fairly self-explanatory. Compile-tested.

---
 kernel/exit.c |   23 ++++++++++++++++++++++-
 1 files changed, 22 insertions(+), 1 deletions(-)
kernel/exit.c +22 -1
index 294b170..89d0892 100644
@@ -710,8 +710,29 @@ static struct task_struct *find_new_reaper(struct task_struct *father)
 
 	if (unlikely(pid_ns->child_reaper == father)) {
 		write_unlock_irq(&tasklist_lock);
-		if (unlikely(pid_ns == &init_pid_ns))
+		if (unlikely(pid_ns == &init_pid_ns)) {
+			/*
+			 * The situation when init segfaults is rather typical.
+			 * Give some useful diagnostics: do we die on signal?
+			 */
+			if (fatal_signal_pending(father)) {
+				const char *msg = "";
+				sigset_t *mask = &father->pending.signal;
+				/* Only force_sig()ned signals kill init */
+				if (sigismember(mask, SIGSEGV))
+					msg = " SIGSEGV";
+				if (sigismember(mask, SIGBUS))
+					msg = " SIGBUS";
+				if (sigismember(mask, SIGILL))
+					msg = " SIGILL";
+				if (sigismember(mask, SIGFPE))
+					msg = " SIGFPE";
+				/* (do we want to check SIGTRAP too?) */
+				printk(KERN_ERR
+					"init received fatal signal%s\n", msg);
+			}
 			panic("Attempted to kill init!");
+		}
 
 		zap_pid_ns_processes(pid_ns);
 		write_lock_irq(&tasklist_lock);
Signature · 1 line
1.7.7.5
#1 lore raw
Quoted 21 lines · Denys Vlasenko

I just received another user's pleas for help when their init mystriously dies. I again explained that they need to check whether it dies because of bad instruction, a segv, or something else.

Which prompted me to make kernel do this first step automatically. We can easily detect when the death is from e.g. SIGILL, and let user know that.

The code is fairly self-explanatory. Compile-tested.

---
 kernel/exit.c |   23 ++++++++++++++++++++++-
 1 files changed, 22 insertions(+), 1 deletions(-)
kernel/exit.c +0 -0
index 294b170..89d0892 100644

kernel/exit.c static struct task_struct *find_new_reaper(struct task_struct *father) · line 718

Quoted 10 lines
kernel/exit.c +6 -1
@@ -710,8 +710,29 @@ static struct task_struct *find_new_reaper(struct task_struct *father)
 
 	if (unlikely(pid_ns->child_reaper == father)) {
 		write_unlock_irq(&tasklist_lock);
-		if (unlikely(pid_ns == &init_pid_ns))
+		if (unlikely(pid_ns == &init_pid_ns)) {
+			/*
+			 * The situation when init segfaults is rather typical.
+			 * Give some useful diagnostics: do we die on signal?
+			 */
+			if (fatal_signal_pending(father)) {

The fatal signal can be already dequeued. Although mostly this works.

kernel/exit.c static struct task_struct *find_new_reaper(struct task_struct *father) · line 729

Quoted 11 lines
kernel/exit.c +11 -0
+				const char *msg = "";
+				sigset_t *mask = &father->pending.signal;
+				/* Only force_sig()ned signals kill init */
+				if (sigismember(mask, SIGSEGV))
+					msg = " SIGSEGV";
+				if (sigismember(mask, SIGBUS))
+					msg = " SIGBUS";
+				if (sigismember(mask, SIGILL))
+					msg = " SIGILL";
+				if (sigismember(mask, SIGFPE))
+					msg = " SIGFPE";

This doesn't look right too. Again, if it was killed by SIGSEGV this signal can be dequeued and not pending.

kernel/exit.c static struct task_struct *find_new_reaper(struct task_struct *father) · line 733

Quoted 4 lines
kernel/exit.c +4 -0
+				/* (do we want to check SIGTRAP too?) */
+				printk(KERN_ERR
+					"init received fatal signal%s\n", msg);
+			}

I'd suggest this trivial change instead,

	-	panic("Attempted to kill init!");
	+	panic("Attempted to kill init! code=%08x\n",
	+		father->signal->group_exit_code ?: father->exit_code);

Oleg.