From: Jeff Dike This patch changes how UML kills ptraced processes in order to be more correct in the presence of the ptrace changes in 2.6.9. It used to be that ptrace stopped processes could simply be killed and they would go away. Now, there's a new run state for ptraced processes which doesn't receive signals until they are PTRACE_KILLed or PTRACE_CONTinued. So, this patch kills the process, as usual, then PTRACE_KILL and PTRACE_CONT. This is done in os_kill_ptrace_process() for use from skas mode, and in tracer() when it sees a child process getting a SIGKILL. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton --- 25-akpm/arch/um/kernel/tt/exec_user.c | 3 ++- 25-akpm/arch/um/kernel/tt/process_kern.c | 5 +++-- 25-akpm/arch/um/kernel/tt/tracer.c | 8 +++++++- 25-akpm/arch/um/os-Linux/process.c | 7 +++++++ 4 files changed, 19 insertions(+), 4 deletions(-) diff -puN arch/um/kernel/tt/exec_user.c~uml-kill-host-processes-properly arch/um/kernel/tt/exec_user.c --- 25/arch/um/kernel/tt/exec_user.c~uml-kill-host-processes-properly Fri Dec 3 13:50:31 2004 +++ 25-akpm/arch/um/kernel/tt/exec_user.c Fri Dec 3 13:50:31 2004 @@ -16,6 +16,7 @@ #include "kern_util.h" #include "user.h" #include "ptrace_user.h" +#include "os.h" void do_exec(int old_pid, int new_pid) { @@ -36,7 +37,7 @@ void do_exec(int old_pid, int new_pid) tracer_panic("do_exec failed to get registers - errno = %d", errno); - kill(old_pid, SIGKILL); + os_kill_ptraced_process(old_pid, 0); if (ptrace(PTRACE_SETOPTIONS, new_pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) tracer_panic("do_exec: PTRACE_SETOPTIONS failed, errno = %d", errno); diff -puN arch/um/kernel/tt/process_kern.c~uml-kill-host-processes-properly arch/um/kernel/tt/process_kern.c --- 25/arch/um/kernel/tt/process_kern.c~uml-kill-host-processes-properly Fri Dec 3 13:50:31 2004 +++ 25-akpm/arch/um/kernel/tt/process_kern.c Fri Dec 3 13:50:31 2004 @@ -65,7 +65,8 @@ void *switch_to_tt(void *prev, void *nex panic("write of switch_pipe failed, err = %d", -err); reading = 1; - if((from->exit_state == EXIT_ZOMBIE) || (from->exit_state == EXIT_DEAD)) + if((from->exit_state == EXIT_ZOMBIE) || + (from->exit_state == EXIT_DEAD)) os_kill_process(os_getpid(), 0); err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c)); @@ -82,7 +83,7 @@ void *switch_to_tt(void *prev, void *nex prev_sched = current->thread.prev_sched; if((prev_sched->exit_state == EXIT_ZOMBIE) || (prev_sched->exit_state == EXIT_DEAD)) - os_kill_ptraced_process(prev_sched->thread.mode.tt.extern_pid, 1); + os_kill_process(prev_sched->thread.mode.tt.extern_pid, 1); /* This works around a nasty race with 'jail'. If we are switching * between two threads of a threaded app and the incoming process diff -puN arch/um/kernel/tt/tracer.c~uml-kill-host-processes-properly arch/um/kernel/tt/tracer.c --- 25/arch/um/kernel/tt/tracer.c~uml-kill-host-processes-properly Fri Dec 3 13:50:31 2004 +++ 25-akpm/arch/um/kernel/tt/tracer.c Fri Dec 3 13:50:31 2004 @@ -319,7 +319,13 @@ int tracer(int (*init_proc)(void *), voi case OP_HALT: unmap_physmem(); kmalloc_ok = 0; - ptrace(PTRACE_KILL, pid, 0, 0); + os_kill_ptraced_process(pid, 0); + /* Now let's reap remaining zombies */ + errno = 0; + do { + waitpid(-1, &status, + WUNTRACED); + } while (errno != ECHILD); return(op == OP_REBOOT); case OP_NONE: printf("Detaching pid %d\n", pid); diff -puN arch/um/os-Linux/process.c~uml-kill-host-processes-properly arch/um/os-Linux/process.c --- 25/arch/um/os-Linux/process.c~uml-kill-host-processes-properly Fri Dec 3 13:50:31 2004 +++ 25-akpm/arch/um/os-Linux/process.c Fri Dec 3 13:50:31 2004 @@ -95,9 +95,16 @@ void os_kill_process(int pid, int reap_c } +/* Kill off a ptraced child by all means available. kill it normally first, + * then PTRACE_KILL it, then PTRACE_CONT it in case it's in a run state from + * which it can't exit directly. + */ + void os_kill_ptraced_process(int pid, int reap_child) { + kill(pid, SIGKILL); ptrace(PTRACE_KILL, pid); + ptrace(PTRACE_CONT, pid); if(reap_child) CATCH_EINTR(waitpid(pid, NULL, 0)); } _