• Oleg Nesterov's avatar
    wait: WSTOPPED|WCONTINUED hangs if a zombie child is traced by real_parent · 377d75da
    Oleg Nesterov authored
    "A zombie is only visible to its ptracer" logic in wait_consider_task()
    is very wrong. Trivial test-case:
    
    	#include <unistd.h>
    	#include <sys/ptrace.h>
    	#include <sys/wait.h>
    	#include <assert.h>
    
    	int main(void)
    	{
    		int child = fork();
    
    		if (!child) {
    			assert(ptrace(PTRACE_TRACEME, 0,0,0) == 0);
    			return 0x23;
    		}
    
    		assert(waitid(P_ALL, child, NULL, WEXITED | WNOWAIT) == 0);
    		assert(waitid(P_ALL, 0, NULL, WSTOPPED) == -1);
    		return 0;
    	}
    
    it hangs in waitpid(WSTOPPED) despite the fact it has a single zombie
    child.  This is because wait_consider_task(ptrace => 0) sees p->ptrace and
    cleares ->notask_error assuming that the debugger should detach and notify
    us.
    
    Change wait_consider_task(ptrace => 0) to pretend that ptrace == T if the
    child is traced by us.  This really simplifies the logic and allows us to
    do more fixes, see the next changes.  This also hides the unwanted group
    stop state automatically, we can remove another ptrace_reparented() check.
    
    Unfortunately, this adds the following behavioural changes:
    
    	1. Before this patch wait(WEXITED | __WNOTHREAD) does not reap
    	   a natural child if it is traced by the caller's sub-thread.
    
    	   Hopefully nobody will ever notice this change, and I think
    	   that nobody should rely on this behaviour anyway.
    
    	2. SIGNAL_STOP_CONTINUED is no longer hidden from debugger if
    	   it is real parent.
    
    	   While this change comes as a side effect, I think it is good
    	   by itself. The group continued state can not be consumed by
    	   another process in this case, it doesn't depend on ptrace,
    	   it doesn't make sense to hide it from real parent.
    
    	   Perhaps we should add the thread_group_leader() check before
    	   wait_task_continued()? May be, but this shouldn't depend on
    	   ptrace_reparented().
    Signed-off-by: default avatarOleg Nesterov <oleg@redhat.com>
    Cc: Al Viro <viro@ZenIV.linux.org.uk>
    Cc: Jan Kratochvil <jan.kratochvil@redhat.com>
    Cc: Lennart Poettering <lpoetter@redhat.com>
    Cc: Michal Schmidt <mschmidt@redhat.com>
    Cc: Roland McGrath <roland@hack.frob.com>
    Cc: Tejun Heo <tj@kernel.org>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    377d75da
exit.c 42.6 KB