[20/21] ns: Restore pid_for_children ns in threads

Submitted by Kirill Tkhai on May 23, 2017, 12:41 p.m.

Details

Message ID 149554328624.12386.5941608805106265077.stgit@localhost.localdomain
State Accepted
Series "Add /proc/[pid]/ns/pid_for_children ns support (and fixes)"
Commit 7e7d485c76654d8e57dc9bf956fedcfa3aa1698f
Headers show

Commit Message

Kirill Tkhai May 23, 2017, 12:41 p.m.
Threads may have different pid_for_children ns.
Allow them to set it after they are created:
just get a pid_ns fd from fdstore, and setns()
to it, after thread creation.

Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
---
 criu/cr-restore.c       |   24 ++++++++++++++++++++++++
 criu/include/restorer.h |    1 +
 criu/pie/restorer.c     |   33 ++++++++++++++++++++++++++++-----
 3 files changed, 53 insertions(+), 5 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/cr-restore.c b/criu/cr-restore.c
index b3d686f3f..17bd9c2d2 100644
--- a/criu/cr-restore.c
+++ b/criu/cr-restore.c
@@ -3035,6 +3035,25 @@  static int prepare_signals(int pid, struct task_restore_args *ta, CoreEntry *lea
 	return ret;
 }
 
+static int get_thread_pid_ns_fd(uint32_t pid_ns_id)
+{
+	struct ns_id *ns;
+	int fd;
+
+	if (current->pid_for_children_ns->id == pid_ns_id)
+		return -2;
+
+	ns = lookup_ns_by_id(pid_ns_id, &pid_ns_desc);
+	BUG_ON(!ns);
+
+	fd = fdstore_get(ns->pid.nsfd_id);
+	if (fd < 0) {
+		pr_err("Can't get pid_ns fd\n");
+		return -1;
+	}
+	return fd;
+}
+
 extern void __gcov_flush(void) __attribute__((weak));
 void __gcov_flush(void) {}
 
@@ -3509,12 +3528,17 @@  static int sigreturn_restore(pid_t pid, struct task_restore_args *task_args, uns
 			task_args->t = thread_args + i;
 			tcore = core;
 			blkset = (void *)&tcore->tc->blk_sigset;
+			thread_args[i].pfc_ns_fd = get_thread_pid_ns_fd(current->ids->pid_for_children_ns_id);
 		} else {
 			tcore = current->core[i];
 			if (tcore->thread_core->has_blk_sigset)
 				blkset = (void *)&tcore->thread_core->blk_sigset;
+			thread_args[i].pfc_ns_fd = get_thread_pid_ns_fd(tcore->ids->pid_for_children_ns_id);
 		}
 
+		if (thread_args[i].pfc_ns_fd == -1)
+			goto err;
+
 		if ((tcore->tc) && thread_args[i].pid[0] != pid) {
 			pr_err("Thread has optional fields present %d\n",
 			       thread_args[i].pid[0]);
diff --git a/criu/include/restorer.h b/criu/include/restorer.h
index 1866bbd82..736ba96a9 100644
--- a/criu/include/restorer.h
+++ b/criu/include/restorer.h
@@ -96,6 +96,7 @@  struct thread_restore_args {
 	unsigned int			siginfo_n;
 
 	int				pdeath_sig;
+	int				pfc_ns_fd;
 
 	struct thread_creds_args	*creds_args;
 } __aligned(64);
diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c
index 736c12504..f6c30d180 100644
--- a/criu/pie/restorer.c
+++ b/criu/pie/restorer.c
@@ -500,7 +500,7 @@  long __export_restore_thread(struct thread_restore_args *args)
 	k_rtsigset_t to_block;
 	unsigned long new_sp;
 	int my_pid = sys_gettid();
-	int i, ret;
+	int i, fd, ret;
 
 	for (i = 0; i < MAX_NS_NESTING; i++)
 		if (args->pid[i] == 0)
@@ -524,6 +524,16 @@  long __export_restore_thread(struct thread_restore_args *args)
 	if (restore_thread_common(args))
 		goto core_restore_end;
 
+	fd = args->pfc_ns_fd;
+	if (fd >= 0) {
+		ret = sys_setns(fd, CLONE_NEWPID);
+		if (ret) {
+			pr_err("Can't setns: ret=%d\n", ret);
+			goto core_restore_end;
+		}
+		sys_close(fd);
+	}
+
 	ret = restore_creds(args->creds_args, args->ta->proc_fd);
 	if (ret)
 		goto core_restore_end;
@@ -1159,7 +1169,7 @@  static int wait_zombies(struct task_restore_args *task_args)
 long __export_restore_task(struct task_restore_args *args)
 {
 	long ret = -1;
-	int i, k;
+	int i, k, fd, self_thread;
 	VmaEntry *vma_entry;
 	unsigned long va;
 	struct restore_vma_io *rio;
@@ -1484,15 +1494,16 @@  long __export_restore_task(struct task_restore_args *args)
 	 * | thread restore proc | thread1 stack | thread1 rt_sigframe |
 	 * +--------------------------------------------------------------------------+
 	 */
-
+	self_thread = 0;
 	if (args->nr_threads > 1) {
 		struct thread_restore_args *thread_args = args->thread_args;
 		long clone_flags = CLONE_VM | CLONE_FILES | CLONE_SIGHAND	|
 				   CLONE_THREAD | CLONE_SYSVSEM | CLONE_FS;
 		long last_pid_len;
 		long parent_tid;
-		int i, fd = -1;
+		int i;
 
+		fd = -1;
 		if (thread_args[0].pid[1] == 0) {
 			/* One level pid ns hierarhy */
 			fd = sys_openat(args->proc_fd, LAST_PID_PATH, O_RDWR, 0);
@@ -1507,8 +1518,10 @@  long __export_restore_task(struct task_restore_args *args)
 		for (i = 0; i < args->nr_threads; i++) {
 			char last_pid_buf[16], *s;
 			/* skip self */
-			if (thread_args[i].pid[0] == args->t->pid[0])
+			if (thread_args[i].pid[0] == args->t->pid[0]) {
+				self_thread = i;
 				continue;
+			}
 
 			if (fd >= 0) {
 				/* One level pid ns hierarhy */
@@ -1606,6 +1619,16 @@  long __export_restore_task(struct task_restore_args *args)
 
 	rst_tcp_socks_all(args);
 
+	fd = args->thread_args[self_thread].pfc_ns_fd;
+	if (fd >= 0) {
+		ret = sys_setns(fd, CLONE_NEWPID);
+		if (ret) {
+			pr_err("Can't setns: ret=%d\n", (int)ret);
+			goto core_restore_end;
+		}
+		sys_close(fd);
+	}
+
 	/* The kernel restricts setting seccomp to uid 0 in the current user
 	 * ns, so we must do this before restore_creds.
 	 */