[CRIU] [PATCH 1/4] ptrace: start tracing processes before restoring creds

Tycho Andersen tycho.andersen at canonical.com
Wed Dec 16 08:15:07 PST 2015


From: Andrew Vagin <avagin at virtuozzo.com>

In order to restore seccomp correctly, we need to do it before
restore_creds() in the restorer blob. But, if the seccomp policy forbids
e.g. prctl, if the task doesn't have SUSPEND_SECCOMP set it will die when
trying to restore creds. To solve this, we break attach_to_tasks up into
two parts: 1. we attach and set SUSPEND_SECCOMP (but let the tasks continue
normally), and then after the RESTORE_CREDS stage we 2. attach to the tasks
and stop them on the final sigreturn.

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

diff --git a/cr-restore.c b/cr-restore.c
index 3c636b9..6815879 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;
@@ -1931,13 +1963,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.5.0



More information about the CRIU mailing list