Skip to content

Commit dc2fd4b

Browse files
oleg-nesterovtorvalds
authored andcommitted
exit: reparent: use ->ptrace_entry rather than ->sibling for EXIT_DEAD tasks
reparent_leader() reuses ->sibling as a list node to add an EXIT_DEAD task into dead_children list we are going to release. This obviously removes the dead task from its real_parent->children list and this is even good; the parent can do nothing with the EXIT_DEAD reparented zombie, it only makes do_wait() slower. But, this also means that it can not be reparented once again, so if its new parent dies too nobody will update ->parent/real_parent, they can point to the freed memory even before release_task() we are going to call, this breaks the code which relies on pid_alive() to access ->real_parent/parent. Fortunately this is mostly theoretical, this can only happen if init or PR_SET_CHILD_SUBREAPER process ignores SIGCHLD and the new parent sub-thread exits right after we drop tasklist_lock. Change this code to use ->ptrace_entry instead, we know that the child is not traced so nobody can ever use this member. This also allows to unify this logic with exit_ptrace(), see the next changes. Note: we really need to change release_task() to nullify real_parent/ parent/group_leader pointers, but we need to change the current users first somehow. And it would be better to reap this zombie immediately but release_task_locked() we need is complicated by proc_flush_task(). Signed-off-by: Oleg Nesterov <oleg@redhat.com> Cc: Aaron Tomlin <atomlin@redhat.com> Cc: Alexey Dobriyan <adobriyan@gmail.com> Cc: "Eric W. Biederman" <ebiederm@xmission.com>, Cc: Sterling Alexander <stalexan@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Roland McGrath <roland@hack.frob.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent a90e984 commit dc2fd4b

File tree

1 file changed

+3
-3
lines changed

1 file changed

+3
-3
lines changed

kernel/exit.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ static void reparent_leader(struct task_struct *father, struct task_struct *p,
548548
p->exit_state == EXIT_ZOMBIE && thread_group_empty(p)) {
549549
if (do_notify_parent(p, p->exit_signal)) {
550550
p->exit_state = EXIT_DEAD;
551-
list_move_tail(&p->sibling, dead);
551+
list_add(&p->ptrace_entry, dead);
552552
}
553553
}
554554

@@ -587,8 +587,8 @@ static void forget_original_parent(struct task_struct *father)
587587

588588
BUG_ON(!list_empty(&father->children));
589589

590-
list_for_each_entry_safe(p, n, &dead_children, sibling) {
591-
list_del_init(&p->sibling);
590+
list_for_each_entry_safe(p, n, &dead_children, ptrace_entry) {
591+
list_del_init(&p->ptrace_entry);
592592
release_task(p);
593593
}
594594
}

0 commit comments

Comments
 (0)