diff --git a/include/linux/sched.h b/include/linux/sched.h index 0917b3df12d53846abc78503cadaa25aae1a0422..fe970cdca83cd793c6fee600982e15661077a64d 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -561,6 +561,8 @@ struct signal_struct { #define SIGNAL_CLD_CONTINUED 0x00000020 #define SIGNAL_CLD_MASK (SIGNAL_CLD_STOPPED|SIGNAL_CLD_CONTINUED) +#define SIGNAL_UNKILLABLE 0x00000040 /* for init: ignore fatal signals */ + /* If true, all threads except ->group_exit_task have pending SIGKILL */ static inline int signal_group_exit(const struct signal_struct *sig) { diff --git a/init/main.c b/init/main.c index 624266b524d41e98c7012a2b2b84d4793744970b..1f4406477f83b88831389fd364a0acfdf50aa14e 100644 --- a/init/main.c +++ b/init/main.c @@ -802,6 +802,8 @@ static int noinline init_post(void) (void) sys_dup(0); (void) sys_dup(0); + current->signal->flags |= SIGNAL_UNKILLABLE; + if (ramdisk_execute_command) { run_init_process(ramdisk_execute_command); printk(KERN_WARNING "Failed to execute %s\n", diff --git a/kernel/signal.c b/kernel/signal.c index 02ef3548aeb086b22b49b3cfa4d68819a9a1d5b5..646a8765696a1ea444c301569dfd67e195da60cd 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -728,7 +728,8 @@ static void complete_signal(int sig, struct task_struct *p, int group) * Found a killable thread. If the signal will be fatal, * then start taking the whole group down immediately. */ - if (sig_fatal(p, sig) && !(signal->flags & SIGNAL_GROUP_EXIT) && + if (sig_fatal(p, sig) && + !(signal->flags & (SIGNAL_UNKILLABLE | SIGNAL_GROUP_EXIT)) && !sigismember(&t->real_blocked, sig) && (sig == SIGKILL || !(t->ptrace & PT_PTRACED))) { /* @@ -1615,7 +1616,8 @@ static int do_signal_stop(int signr) } else { struct task_struct *t; - if (!likely(sig->flags & SIGNAL_STOP_DEQUEUED) || + if (unlikely((sig->flags & (SIGNAL_STOP_DEQUEUED | SIGNAL_UNKILLABLE)) + != SIGNAL_STOP_DEQUEUED) || unlikely(signal_group_exit(sig))) return 0; /* @@ -1761,7 +1763,8 @@ int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka, /* * Global init gets no signals it doesn't want. */ - if (is_global_init(current)) + if (unlikely(signal->flags & SIGNAL_UNKILLABLE) && + !signal_group_exit(signal)) continue; if (sig_kernel_stop(signr)) {