[CRIU] [PATCH v4 03/31] ns: Set nested namespaces hookups

Kirill Tkhai ktkhai at virtuozzo.com
Wed Feb 22 03:30:51 PST 2017


Introduce ns_id::parent and assign a pointer to parent
for every ns except NS_CRIU and NS_ROOT.
Also populate user_ns for pid_ns.

v4: Set "ret = -1" on one of the error pathes.
    Add comment about user_ns finding.

Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
---
 criu/include/namespaces.h |   12 ++++++
 criu/namespaces.c         |   92 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 104 insertions(+)

diff --git a/criu/include/namespaces.h b/criu/include/namespaces.h
index 1b454e0c1..69df0313b 100644
--- a/criu/include/namespaces.h
+++ b/criu/include/namespaces.h
@@ -1,6 +1,8 @@
 #ifndef __CR_NS_H__
 #define __CR_NS_H__
 
+#include <sys/ioctl.h>
+
 #include "common/compiler.h"
 #include "files.h"
 #include "common/list.h"
@@ -40,6 +42,12 @@
 
 #define EXTRA_SIZE	20
 
+#ifndef NSIO
+#define NSIO    0xb7
+#define NS_GET_USERNS   _IO(NSIO, 0x1)
+#define NS_GET_PARENT   _IO(NSIO, 0x2)
+#endif
+
 struct ns_desc {
 	unsigned int	cflag;
 	char		*str;
@@ -76,6 +84,10 @@ struct ns_id {
 	unsigned int id;
 	pid_t ns_pid;
 	struct ns_desc *nd;
+	struct ns_id *parent;
+	struct list_head children;
+	struct list_head siblings;
+	struct ns_id *user_ns;
 	struct ns_id *next;
 	enum ns_type type;
 
diff --git a/criu/namespaces.c b/criu/namespaces.c
index b22162a3a..dd9fb7680 100644
--- a/criu/namespaces.c
+++ b/criu/namespaces.c
@@ -13,6 +13,7 @@
 #include <sys/stat.h>
 #include <limits.h>
 #include <errno.h>
+#include <sys/ioctl.h>
 
 #include "page.h"
 #include "rst-malloc.h"
@@ -302,6 +303,8 @@ struct ns_id *rst_new_ns_id(unsigned int id, pid_t pid,
 		nsid->type = type;
 		nsid_add(nsid, nd, id, pid);
 		nsid->ns_populated = false;
+		INIT_LIST_HEAD(&nsid->children);
+		INIT_LIST_HEAD(&nsid->siblings);
 	}
 
 	return nsid;
@@ -421,6 +424,8 @@ static unsigned int generate_ns_id(int pid, unsigned int kid, struct ns_desc *nd
 	nsid->type = type;
 	nsid->kid = kid;
 	nsid->ns_populated = true;
+	INIT_LIST_HEAD(&nsid->children);
+	INIT_LIST_HEAD(&nsid->siblings);
 	nsid_add(nsid, nd, ns_next_id++, pid);
 
 found:
@@ -661,6 +666,93 @@ int dump_task_ns_ids(struct pstree_item *item)
 	return 0;
 }
 
+static int set_ns_opt(int ns_fd, unsigned ioc, struct ns_id **ns, struct ns_desc *nd)
+{
+	int opt_fd, ret = -1;
+	struct stat st;
+
+	opt_fd = ioctl(ns_fd, ioc);
+	if (opt_fd < 0) {
+		pr_info("Can't do ns ioctl %x\n", ioc);
+		return -errno;
+	}
+	if (fstat(opt_fd, &st) < 0) {
+		pr_perror("Unable to stat on ns fd");
+		ret = -errno;
+		goto out;
+	}
+	*ns = lookup_ns_by_kid(st.st_ino, nd);
+	if (!*ns) {
+		pr_err("Namespaces hierarhies with holes are not supported\n");
+		ret = -EINVAL;
+		goto out;
+	}
+	ret = 0;
+out:
+	close(opt_fd);
+	return ret;
+}
+
+static int set_ns_hookups(struct ns_id *ns)
+{
+	struct ns_desc *nd = ns->nd;
+	struct ns_id *u_ns;
+	int fd, ret = -1;
+
+	fd = open_proc(ns->ns_pid, "ns/%s", nd->str);
+	if (fd < 0) {
+		pr_perror("Can't open %s, pid %d", nd->str, ns->ns_pid);
+		return -1;
+	}
+
+	if (ns->type != NS_ROOT && (nd == &pid_ns_desc || nd == &user_ns_desc)) {
+		if (set_ns_opt(fd, NS_GET_PARENT, &ns->parent, nd) < 0)
+			goto out;
+		if (ns->parent && ns->parent->type == NS_CRIU) {
+			pr_err("Wrong determined NS_ROOT, or root_item has NS_OTHER user_ns\n");
+			goto out;
+		}
+		list_add(&ns->siblings, &ns->parent->children);
+	}
+
+	if (nd != &user_ns_desc) {
+		ret = set_ns_opt(fd, NS_GET_USERNS, &ns->user_ns, &user_ns_desc);
+		if (ret == -ENOTTY) {
+			u_ns = NULL;
+			if (root_ns_mask & CLONE_NEWUSER) {
+				/*
+				 * Assume, we have the only user_ns. If it's not so,
+				 * we'll later fail on NS_GET_PARENT for the second user_ns.
+				 */
+				pr_info("Can't get user_ns of %s %u, assuming NS_ROOT\n",
+					nd->str, ns->id);
+				for (u_ns = ns_ids; u_ns; u_ns = u_ns->next) {
+					if (u_ns->nd == &user_ns_desc && u_ns->type == NS_ROOT)
+						break;
+				}
+				if (!u_ns) {
+					pr_err("Can't find root user_ns\n");
+					goto out;
+				}
+			}
+			ns->user_ns = u_ns;
+		} else if (ret < 0) {
+			goto out;
+		} else if (ns->user_ns->type == NS_CRIU) {
+			if (root_ns_mask & CLONE_NEWUSER) {
+				pr_err("Must not be criu user_ns\n");
+				ret = -1;
+				goto out;
+			}
+			ns->user_ns = NULL;
+		}
+	}
+	ret = 0;
+out:
+	close(fd);
+	return ret;
+}
+
 static UsernsEntry userns_entry = USERNS_ENTRY__INIT;
 #define INVALID_ID (~0U)
 



More information about the CRIU mailing list