lkml.org 
[lkml]   [2009]   [Jan]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH 3/4] reparent_thread: fix a zombie leak if /sbin/init ignores SIGCHLD
    If /sbin/init ignores SIGCHLD and we re-parent a zombie, it is leaked.
    reparent_thread() does do_notify_parent() which sets ->exit_signal = -1
    in this case. This means that nobody except us can reap it, the detached
    task is not visible to do_wait().

    Change reparent_thread() to return a boolean (like __pthread_detach) to
    indicate that the thread is dead and must be released. Also change
    forget_original_parent() to add the child to ptrace_dead list in this
    case.

    The naming becomes insane, the next patch does the cleanup.

    Signed-off-by: Oleg Nesterov <oleg@redhat.com>

    --- 6.29-rc3/kernel/exit.c~7_FIX_INIT_IGN_CHLD 2009-01-29 06:57:09.000000000 +0100
    +++ 6.29-rc3/kernel/exit.c 2009-01-29 08:03:18.000000000 +0100
    @@ -804,8 +804,11 @@ static void ptrace_exit_finish(struct ta
    }
    }

    -static void reparent_thread(struct task_struct *p, struct task_struct *father)
    +/* Returns nonzero if the child should be released. */
    +static int reparent_thread(struct task_struct *p, struct task_struct *father)
    {
    + int dead;
    +
    if (p->pdeath_signal)
    /* We already hold the tasklist_lock here. */
    group_send_sig_info(p->pdeath_signal, SEND_SIG_NOINFO, p);
    @@ -813,12 +816,12 @@ static void reparent_thread(struct task_
    list_move_tail(&p->sibling, &p->real_parent->children);

    if (task_detached(p))
    - return;
    + return 0;
    /* If this is a threaded reparent there is no need to
    * notify anyone anything has happened.
    */
    if (same_thread_group(p->real_parent, father))
    - return;
    + return 0;

    /* We don't want people slaying init. */
    p->exit_signal = SIGCHLD;
    @@ -826,11 +829,19 @@ static void reparent_thread(struct task_
    /* If we'd notified the old parent about this child's death,
    * also notify the new parent.
    */
    + dead = 0;
    if (!p->ptrace &&
    - p->exit_state == EXIT_ZOMBIE && thread_group_empty(p))
    + p->exit_state == EXIT_ZOMBIE && thread_group_empty(p)) {
    do_notify_parent(p, p->exit_signal);
    + if (task_detached(p)) {
    + p->exit_state = EXIT_DEAD;
    + dead = 1;
    + }
    + }

    kill_orphaned_pgrp(p, father);
    +
    + return dead;
    }

    /*
    @@ -890,7 +901,8 @@ static void forget_original_parent(struc
    BUG_ON(p->ptrace);
    p->parent = p->real_parent;
    }
    - reparent_thread(p, father);
    + if (reparent_thread(p, father))
    + list_add(&p->ptrace_entry, &ptrace_dead);;
    }

    write_unlock_irq(&tasklist_lock);


    \
     
     \ /
      Last update: 2009-01-29 09:11    [W:0.024 / U:92.588 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site