From: Eric W. Biederman After looking at the problem of init calling exec some more I figured out an easy way to make the code work. The actual symptom without out this patch is that all threads will die except pid == 1, and the thread calling exec. The thread calling exec will wait forever for pid == 1 to die. Since pid == 1 does not install a handler for SIGKILL it will never die. This modifies the tests for init from current->pid == 1 to the equivalent current == child_reaper. And then it causes exec in the ugly case to modify child_reaper. The only weird symptom is that you wind up with an init process that doesn't have the oldest start time on the box. Signed-off-by: Eric W. Biederman Cc: Oleg Nesterov Signed-off-by: Andrew Morton --- fs/exec.c | 13 ++++++++++++- kernel/exit.c | 2 +- kernel/signal.c | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff -puN fs/exec.c~exec-allow-init-to-exec-from-any-thread fs/exec.c --- devel/fs/exec.c~exec-allow-init-to-exec-from-any-thread 2006-02-23 19:41:26.000000000 -0800 +++ devel-akpm/fs/exec.c 2006-02-23 19:41:26.000000000 -0800 @@ -660,12 +660,23 @@ static int de_thread(struct task_struct struct dentry *proc_dentry1, *proc_dentry2; unsigned long ptrace; + leader = current->group_leader; + /* + * If our leader is the child_reaper become + * the child_reaper and resend SIGKILL signal. + */ + if (unlikely(leader == child_reaper)) { + write_lock(&tasklist_lock); + child_reaper = current; + zap_other_threads(current); + write_unlock(&tasklist_lock); + } + /* * Wait for the thread group leader to be a zombie. * It should already be zombie at this point, most * of the time. */ - leader = current->group_leader; while (leader->exit_state != EXIT_ZOMBIE) yield(); diff -puN kernel/exit.c~exec-allow-init-to-exec-from-any-thread kernel/exit.c --- devel/kernel/exit.c~exec-allow-init-to-exec-from-any-thread 2006-02-23 19:41:26.000000000 -0800 +++ devel-akpm/kernel/exit.c 2006-02-23 19:41:26.000000000 -0800 @@ -805,7 +805,7 @@ fastcall NORET_TYPE void do_exit(long co panic("Aiee, killing interrupt handler!"); if (unlikely(!tsk->pid)) panic("Attempted to kill the idle task!"); - if (unlikely(tsk->pid == 1)) + if (unlikely(tsk == child_reaper)) panic("Attempted to kill init!"); if (tsk->io_context) exit_io_context(); diff -puN kernel/signal.c~exec-allow-init-to-exec-from-any-thread kernel/signal.c --- devel/kernel/signal.c~exec-allow-init-to-exec-from-any-thread 2006-02-23 19:41:26.000000000 -0800 +++ devel-akpm/kernel/signal.c 2006-02-23 19:41:26.000000000 -0800 @@ -1990,7 +1990,7 @@ relock: continue; /* Init gets no signals it doesn't want. */ - if (current->pid == 1) + if (current == child_reaper) continue; if (sig_kernel_stop(signr)) { _