[CRIU] is CR_STATE_RESTORE_CREDS necessary?

Andrew Vagin avagin at virtuozzo.com
Tue Dec 15 01:26:16 PST 2015


Hi Tycho,

Coull you take a look at the attached patch? Does it fix your problem?

On Mon, Dec 14, 2015 at 09:07:43AM -0700, Tycho Andersen wrote:
> On Mon, Dec 14, 2015 at 10:14:49AM +0300, Andrew Vagin wrote:
> > On Fri, Dec 11, 2015 at 08:09:57AM -0700, Tycho Andersen wrote:
> > > On Fri, Dec 11, 2015 at 05:48:42PM +0300, Andrew Vagin wrote:
> > > > On Fri, Dec 11, 2015 at 12:11:10AM +0300, Pavel Emelyanov wrote:
> > > > > Yes, that's clear -- we need global final sync point before total
> > > > > unfreeze and resume.
> > > 
> > > Why doesn't CR_STATE_COMPLETE work for this? Doesn't the restorer wait
> > > once it finishes CR_STATE_RESTORE_CREDS until it gets the signal for
> > > CR_STATE_COMPLETE?
> > 
> > Because CRIU doesn't wait when the CR_STATE_COMPLETE stage will be
> > completed.
> 
> Oh, duh :)
> 
> > > But this is really because of the network, not because of the creds.
> > > What if we s/CR_STATE_RESTORE_CREDS/CR_STATE_NETWORK_UNLOCK, and in
> > > the restorer only do rst_tcp_socks_all() here, and move all the creds
> > > restore after CR_STATE_NETWORK_UNLOCK, when the main task sends
> > > CR_STATE_COMPLETE.
> > 
> > I don't understand this. Do you want to restore creds after
> > CR_STATE_COMPLETE?
> 
> No, I just want to restore creds after restore_seccomp, but that needs
> seccomp suspended in order to work. Here's three commits:
> 
> https://github.com/tych0/criu/commits/seccomp-setuid
> 
> the first one adds a setuid() call to make it fail, the second moves
> the restore_seccomp call to the "right" place causing it to pass
> again. But then if we change the seccomp policy slightly, we can get
> it to fail.
> 
> What I'm after is just a way to solve this problem.
> 
> > > 
> > > The one problem this doesn't solve is someone mentioned in the thread
> > > that there was an issue about resuming some tasks before other tasks
> > > had their creds restored. I didn't understand this point, isn't this
> > > prevented by the wait on __NR_rt_sigreturn (except in the case where
> > > criu is itself ptraced, but I'm ignoring that one because I don't
> > > think it's a use case other than for debugging).
> > 
> > Pls, don't ignore this usecases, it is enought critical to take it
> > into account.
> 
> As a real use case, or just for debugging? For just debugging, I think
> it is ok if some things don't work correctly in this state right?
> 
> Tycho
-------------- next part --------------
>From 1189841f8e78eb93d771dbce468afffa6a4fd879 Mon Sep 17 00:00:00 2001
From: Andrew Vagin <avagin at virtuozzo.com>
Date: Tue, 15 Dec 2015 12:20:17 +0300
Subject: [PATCH] ptrace: start tracing processes before restoring creds

Signed-off-by: Andrew Vagin <avagin at virtuozzo.com>
---
 cr-restore.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 47 insertions(+), 14 deletions(-)

diff --git a/cr-restore.c b/cr-restore.c
index aaa9bf2..882fd5d 100644
--- a/cr-restore.c
+++ b/cr-restore.c
@@ -1645,13 +1645,13 @@ static int restore_switch_stage(int next_stage)
 	return restore_wait_inprogress_tasks();
 }
 
-static int attach_to_tasks(bool root_seized, enum trace_flags *flag)
+static int attach_to_tasks(bool root_seized)
 {
 	struct pstree_item *item;
 
 	for_each_pstree_item(item) {
 		pid_t pid = item->pid.real;
-		int status, i, ret;
+		int status, i;
 
 		if (!task_alive(item))
 			continue;
@@ -1663,21 +1663,16 @@ static int attach_to_tasks(bool root_seized, enum trace_flags *flag)
 			pid = item->threads[i].real;
 
 			if (item != root_item || !root_seized || i != 0) {
-				if (ptrace(PTRACE_ATTACH, pid, 0, 0)) {
+				if (ptrace(PTRACE_SEIZE, pid, 0, 0)) {
 					pr_perror("Can't attach to %d", pid);
 					return -1;
 				}
-			} else {
-				/*
-				 * Root item is SEIZE-d, so we only need
-				 * to stop one (INTERRUPT) to make wait4
-				 * and SYSCALL below work.
-				 */
-				if (ptrace(PTRACE_INTERRUPT, pid, 0, 0)) {
-					pr_perror("Can't interrupt the %d task", pid);
-					return -1;
-				}
 			}
+			if (ptrace(PTRACE_INTERRUPT, pid, 0, 0)) {
+				pr_perror("Can't interrupt the %d task", pid);
+				return -1;
+			}
+
 
 			if (wait4(pid, &status, __WALL, NULL) != pid) {
 				pr_perror("waitpid(%d) failed", pid);
@@ -1694,6 +1689,43 @@ static int attach_to_tasks(bool root_seized, enum trace_flags *flag)
 			if (rsti(item)->has_seccomp && suspend_seccomp(pid) < 0)
 				pr_err("failed to suspend seccomp, restore will probably fail...\n");
 
+			if (ptrace(PTRACE_CONT, pid, NULL, NULL) ) {
+				pr_perror("Unable to resume %d", pid);
+				return -1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int catch_tasks(bool root_seized, enum trace_flags *flag)
+{
+	struct pstree_item *item;
+
+	for_each_pstree_item(item) {
+		pid_t pid = item->pid.real;
+		int status, i, ret;
+
+		if (!task_alive(item))
+			continue;
+
+		if (parse_threads(item->pid.real, &item->threads, &item->nr_threads))
+			return -1;
+
+		for (i = 0; i < item->nr_threads; i++) {
+			pid = item->threads[i].real;
+
+			if (ptrace(PTRACE_INTERRUPT, pid, 0, 0)) {
+				pr_perror("Can't interrupt the %d task", pid);
+				return -1;
+			}
+
+			if (wait4(pid, &status, __WALL, NULL) != pid) {
+				pr_perror("waitpid(%d) failed", pid);
+				return -1;
+			}
+
 			ret = ptrace_stop_pie(pid, rsti(item)->breakpoint, flag);
 			if (ret < 0)
 				return -1;
@@ -1942,13 +1974,14 @@ static int restore_root_task(struct pstree_item *init)
 	 * -------------------------------------------------------------
 	 * Below this line nothing should fail, because network is unlocked
 	 */
+	attach_to_tasks(root_as_sibling);
 
 	ret = restore_switch_stage(CR_STATE_RESTORE_CREDS);
 	BUG_ON(ret);
 
 	timing_stop(TIME_RESTORE);
 
-	ret = attach_to_tasks(root_as_sibling, &flag);
+	ret = catch_tasks(root_as_sibling, &flag);
 
 	pr_info("Restore finished successfully. Resuming tasks.\n");
 	futex_set_and_wake(&task_entries->start, CR_STATE_COMPLETE);
-- 
2.4.3



More information about the CRIU mailing list