lkml.org 
[lkml]   [2012]   [Jan]   [5]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[72/73] ptrace: partially fix the do_wait(WEXITED) vs EXIT_DEAD->EXIT_ZOMBIE race
    3.0-stable review patch.  If anyone has any objections, please let me know.

    ------------------
    Content-Length: 2354
    Lines: 86

    From: Oleg Nesterov <oleg@redhat.com>

    commit 50b8d257486a45cba7b65ca978986ed216bbcc10 upstream.

    Test-case:

    int main(void)
    {
    int pid, status;

    pid = fork();
    if (!pid) {
    for (;;) {
    if (!fork())
    return 0;
    if (waitpid(-1, &status, 0) < 0) {
    printf("ERR!! wait: %m\n");
    return 0;
    }
    }
    }

    assert(ptrace(PTRACE_ATTACH, pid, 0,0) == 0);
    assert(waitpid(-1, NULL, 0) == pid);

    assert(ptrace(PTRACE_SETOPTIONS, pid, 0,
    PTRACE_O_TRACEFORK) == 0);

    do {
    ptrace(PTRACE_CONT, pid, 0, 0);
    pid = waitpid(-1, NULL, 0);
    } while (pid > 0);

    return 1;
    }

    It fails because ->real_parent sees its child in EXIT_DEAD state
    while the tracer is going to change the state back to EXIT_ZOMBIE
    in wait_task_zombie().

    The offending commit is 823b018e which moved the EXIT_DEAD check,
    but in fact we should not blame it. The original code was not
    correct as well because it didn't take ptrace_reparented() into
    account and because we can't really trust ->ptrace.

    This patch adds the additional check to close this particular
    race but it doesn't solve the whole problem. We simply can't
    rely on ->ptrace in this case, it can be cleared if the tracer
    is multithreaded by the exiting ->parent.

    I think we should kill EXIT_DEAD altogether, we should always
    remove the soon-to-be-reaped child from ->children or at least
    we should never do the DEAD->ZOMBIE transition. But this is too
    complex for 3.2.

    Reported-and-tested-by: Denys Vlasenko <vda.linux@googlemail.com>
    Tested-by: Lukasz Michalik <lmi@ift.uni.wroc.pl>
    Acked-by: Tejun Heo <tj@kernel.org>
    Signed-off-by: Oleg Nesterov <oleg@redhat.com>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

    ---
    kernel/exit.c | 9 ++++++++-
    1 file changed, 8 insertions(+), 1 deletion(-)

    --- a/kernel/exit.c
    +++ b/kernel/exit.c
    @@ -1553,8 +1553,15 @@ static int wait_consider_task(struct wai
    }

    /* dead body doesn't have much to contribute */
    - if (p->exit_state == EXIT_DEAD)
    + if (unlikely(p->exit_state == EXIT_DEAD)) {
    + /*
    + * But do not ignore this task until the tracer does
    + * wait_task_zombie()->do_notify_parent().
    + */
    + if (likely(!ptrace) && unlikely(ptrace_reparented(p)))
    + wo->notask_error = 0;
    return 0;
    + }

    /* slay zombie? */
    if (p->exit_state == EXIT_ZOMBIE) {



    \
     
     \ /
      Last update: 2012-01-05 23:49    [W:0.026 / U:0.340 seconds]
    ©2003-2017 Jasper Spaans. hosted at Digital OceanAdvertise on this site