aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/exit.c33
-rw-r--r--kernel/fork.c3
-rw-r--r--kernel/sys.c8
3 files changed, 39 insertions, 5 deletions
diff --git a/kernel/exit.c b/kernel/exit.c
index 16b07bfac224..456329fd4ea3 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -687,11 +687,11 @@ static void exit_mm(struct task_struct * tsk)
687} 687}
688 688
689/* 689/*
690 * When we die, we re-parent all our children. 690 * When we die, we re-parent all our children, and try to:
691 * Try to give them to another thread in our thread 691 * 1. give them to another thread in our thread group, if such a member exists
692 * group, and if no such member exists, give it to 692 * 2. give it to the first ancestor process which prctl'd itself as a
693 * the child reaper process (ie "init") in our pid 693 * child_subreaper for its children (like a service manager)
694 * space. 694 * 3. give it to the init process (PID 1) in our pid namespace
695 */ 695 */
696static struct task_struct *find_new_reaper(struct task_struct *father) 696static struct task_struct *find_new_reaper(struct task_struct *father)
697 __releases(&tasklist_lock) 697 __releases(&tasklist_lock)
@@ -722,6 +722,29 @@ static struct task_struct *find_new_reaper(struct task_struct *father)
722 * forget_original_parent() must move them somewhere. 722 * forget_original_parent() must move them somewhere.
723 */ 723 */
724 pid_ns->child_reaper = init_pid_ns.child_reaper; 724 pid_ns->child_reaper = init_pid_ns.child_reaper;
725 } else if (father->signal->has_child_subreaper) {
726 struct task_struct *reaper;
727
728 /*
729 * Find the first ancestor marked as child_subreaper.
730 * Note that the code below checks same_thread_group(reaper,
731 * pid_ns->child_reaper). This is what we need to DTRT in a
732 * PID namespace. However we still need the check above, see
733 * http://marc.info/?l=linux-kernel&m=131385460420380
734 */
735 for (reaper = father->real_parent;
736 reaper != &init_task;
737 reaper = reaper->real_parent) {
738 if (same_thread_group(reaper, pid_ns->child_reaper))
739 break;
740 if (!reaper->signal->is_child_subreaper)
741 continue;
742 thread = reaper;
743 do {
744 if (!(thread->flags & PF_EXITING))
745 return reaper;
746 } while_each_thread(reaper, thread);
747 }
725 } 748 }
726 749
727 return pid_ns->child_reaper; 750 return pid_ns->child_reaper;
diff --git a/kernel/fork.c b/kernel/fork.c
index 37674ec55cde..b9372a0bff18 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1051,6 +1051,9 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
1051 sig->oom_score_adj = current->signal->oom_score_adj; 1051 sig->oom_score_adj = current->signal->oom_score_adj;
1052 sig->oom_score_adj_min = current->signal->oom_score_adj_min; 1052 sig->oom_score_adj_min = current->signal->oom_score_adj_min;
1053 1053
1054 sig->has_child_subreaper = current->signal->has_child_subreaper ||
1055 current->signal->is_child_subreaper;
1056
1054 mutex_init(&sig->cred_guard_mutex); 1057 mutex_init(&sig->cred_guard_mutex);
1055 1058
1056 return 0; 1059 return 0;
diff --git a/kernel/sys.c b/kernel/sys.c
index 888d227fd195..9eb7fcab8df6 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1962,6 +1962,14 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
1962 case PR_SET_MM: 1962 case PR_SET_MM:
1963 error = prctl_set_mm(arg2, arg3, arg4, arg5); 1963 error = prctl_set_mm(arg2, arg3, arg4, arg5);
1964 break; 1964 break;
1965 case PR_SET_CHILD_SUBREAPER:
1966 me->signal->is_child_subreaper = !!arg2;
1967 error = 0;
1968 break;
1969 case PR_GET_CHILD_SUBREAPER:
1970 error = put_user(me->signal->is_child_subreaper,
1971 (int __user *) arg2);
1972 break;
1965 default: 1973 default:
1966 error = -EINVAL; 1974 error = -EINVAL;
1967 break; 1975 break;