• Oleg Nesterov's avatar
    wait_task_stopped: simplify and fix races with SIGCONT/SIGKILL/untrace · ee7c82da
    Oleg Nesterov authored
    wait_task_stopped() has multiple races with SIGCONT/SIGKILL.  tasklist_lock
    does not pin the child in TASK_TRACED/TASK_STOPPED stated, almost all info
    reported (including exit_code) may be wrong.
    
    In fact, the code under write_lock_irq(tasklist_lock) is not safe.  The child
    may be PTRACE_DETACH'ed at this time by another subthread, in that case it is
    possible we are no longer its ->parent.
    
    Change wait_task_stopped() to take ->siglock before inspecting the task.  This
    guarantees that the child can't resume and (for example) clear its
    ->exit_code, so we don't need to use xchg(&p->exit_code) and re-check.  The
    only exception is ptrace_stop() which changes ->state and ->exit_code without
    ->siglock held during abort.  But this can only happen if both the tracer and
    the tracee are dying (coredump is in progress), we don't care.
    
    With this patch wait_task_stopped() doesn't move the child to the end of
    the ->parent list on success.  This optimization could be restored, but
    in that case we have to take write_lock(tasklist) and do some nasty
    checks.
    
    Also change the do_wait() since we don't return EAGAIN any longer.
    
    [akpm@linux-foundation.org: fix up after Willy renamed everything]
    Signed-off-by: default avatarOleg Nesterov <oleg@tv-sign.ru>
    Cc: Roland McGrath <roland@redhat.com>
    Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
    Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
    ee7c82da
exit.c 42.4 KB