[Devel] [PATCH RHEL7 COMMIT] ms/exit: fix the setns() && PR_SET_CHILD_SUBREAPER interaction

Konstantin Khorenko khorenko at virtuozzo.com
Mon Jun 20 21:12:50 MSK 2022


The commit is pushed to "branch-rh7-3.10.0-1160.62.1.vz7.187.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-1160.62.1.vz7.187.5
------>
commit a9cf6573bf2285eca795c8aac3ad60304c0d87b9
Author: Oleg Nesterov <oleg at redhat.com>
Date:   Wed Jun 15 17:54:20 2022 +0300

    ms/exit: fix the setns() && PR_SET_CHILD_SUBREAPER interaction
    
    find_new_reaper() checks same_thread_group(reaper, child_reaper) to
    prevent the cross-namespace reparenting but this is not enough if the
    exiting parent was injected by setns() + fork().
    
    Suppose we have a process P in the root namespace and some namespace X.
    P does setns() to enter the X namespace, and forks the child C.
    C forks a grandchild G and exits.
    
    The grandchild G should be re-parented to X->child_reaper, but in this
    case the ->real_parent chain does not lead to ->child_reaper, so it will
    be wrongly reparanted to P's sub-reaper or a global init.
    
    Signed-off-by: Oleg Nesterov <oleg at redhat.com>
    Signed-off-by: Eric W. Biederman <ebiederm at xmission.com>
    
    (cherry picked from ms commit c6c70f4455d1eda91065e93cc4f7eddf4499b105)
    Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
    
    =================
    Patchset description:
    vz7: fix child-reaper reparenting
    
    Forth patch is needed as kernel can reparent process to a dead thread
    which is wrong.
    
    Third patch is needed as kernel could reparent process from father from
    one pidns to process from different pidns, which creates configurations
    not supported by CRIU. Found it when reproducing problem from CRIU
    mainstream issue in VZ7 ct.
    
    https://github.com/checkpoint-restore/criu/issues/1914
    
    First and Second are just to make it apply cleaner.
    
    Oleg Nesterov (4):
      exit: reparent: fix the cross-namespace PR_SET_CHILD_SUBREAPER
        reparenting
      exit: reparent: document the ->has_child_subreaper checks
      exit: fix the setns() && PR_SET_CHILD_SUBREAPER interaction
      exit: reparent: fix the dead-parent PR_SET_CHILD_SUBREAPER reparenting
---
 kernel/exit.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/kernel/exit.c b/kernel/exit.c
index b87564b77011..4ba3a108d449 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -642,16 +642,19 @@ static struct task_struct *find_new_reaper(struct task_struct *father)
 	}
 
 	if (father->signal->has_child_subreaper) {
+		unsigned int ns_level = task_pid(father)->level;
 		struct task_struct *reaper;
 		/*
 		 * Find the first ->is_child_subreaper ancestor in our pid_ns.
-		 * We start from father to ensure we can not look into another
-		 * namespace, this is safe because all its threads are dead.
+		 * We can't check reaper != child_reaper to ensure we do not
+		 * cross the namespaces, the exiting parent could be injected
+		 * by setns() + fork().
+		 * We check pid->level, this is slightly more efficient than
+		 * task_active_pid_ns(reaper) != task_active_pid_ns(father).
 		 */
-		for (reaper = father;
-		     !same_thread_group(reaper, pid_ns->child_reaper);
+		for (reaper = father->real_parent;
+		     task_pid(reaper)->level == ns_level;
 		     reaper = reaper->real_parent) {
-			/* call_usermodehelper() descendants need this check */
 			if (reaper == &init_task)
 				break;
 			if (!reaper->signal->is_child_subreaper)


More information about the Devel mailing list