[v3,05/33] ns: Set nested namespaces hookups

Submitted by Kirill Tkhai on Feb. 16, 2017, 12:07 p.m.

Details

Message ID 148724683914.22444.10061770503087043032.stgit@localhost.localdomain
State New
Series "Nested user namespaces support"
Headers show

Commit Message

Kirill Tkhai Feb. 16, 2017, 12:07 p.m.
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.

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

Patch hide | download patch | download mbox

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 9e61c9481..c4ef52733 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,88 @@  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) {
+			pr_info("Can't get user_ns of %s %u, assuming NS_ROOT\n",
+					nd->str, ns->id);
+			u_ns = NULL;
+			if (root_ns_mask & CLONE_NEWUSER) {
+				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");
+				goto out;
+			}
+			ns->user_ns = NULL;
+		}
+	}
+	ret = 0;
+out:
+	close(fd);
+	return ret;
+}
+
 static UsernsEntry userns_entry = USERNS_ENTRY__INIT;
 #define INVALID_ID (~0U)
 

Comments

Andrey Vagin Feb. 21, 2017, 5:45 a.m.
On Thu, Feb 16, 2017 at 03:07:19PM +0300, Kirill Tkhai wrote:
> 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.
> 
> Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
> ---
>  criu/include/namespaces.h |   12 ++++++
>  criu/namespaces.c         |   87 +++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 99 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 9e61c9481..c4ef52733 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,88 @@ 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) {
> +			pr_info("Can't get user_ns of %s %u, assuming NS_ROOT\n",
> +					nd->str, ns->id);

It is possible only if we dump only one userns.

> +			u_ns = NULL;
> +			if (root_ns_mask & CLONE_NEWUSER) {
> +				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 is zero here

> +				goto out;
> +			}
> +			ns->user_ns = NULL;
> +		}
> +	}
> +	ret = 0;
> +out:
> +	close(fd);
> +	return ret;
> +}
> +
>  static UsernsEntry userns_entry = USERNS_ENTRY__INIT;
>  #define INVALID_ID (~0U)
>  
> 
> _______________________________________________
> CRIU mailing list
> CRIU@openvz.org
> https://lists.openvz.org/mailman/listinfo/criu
Kirill Tkhai Feb. 21, 2017, 11:53 a.m.
On 21.02.2017 08:45, Andrei Vagin wrote:
> On Thu, Feb 16, 2017 at 03:07:19PM +0300, Kirill Tkhai wrote:
>> 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.
>>
>> Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
>> ---
>>  criu/include/namespaces.h |   12 ++++++
>>  criu/namespaces.c         |   87 +++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 99 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 9e61c9481..c4ef52733 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,88 @@ 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) {
>> +			pr_info("Can't get user_ns of %s %u, assuming NS_ROOT\n",
>> +					nd->str, ns->id);
> 
> It is possible only if we dump only one userns.

Sure, and if we have several user_ns, we'll fail on NS_GET_PARENT made for one of them.

>> +			u_ns = NULL;
>> +			if (root_ns_mask & CLONE_NEWUSER) {
>> +				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 is zero here

Yeah, I'll fix that.

> 
>> +				goto out;
>> +			}
>> +			ns->user_ns = NULL;
>> +		}
>> +	}
>> +	ret = 0;
>> +out:
>> +	close(fd);
>> +	return ret;
>> +}
>> +
>>  static UsernsEntry userns_entry = USERNS_ENTRY__INIT;
>>  #define INVALID_ID (~0U)
>>  
>>
>> _______________________________________________
>> CRIU mailing list
>> CRIU@openvz.org
>> https://lists.openvz.org/mailman/listinfo/criu
Andrey Vagin Feb. 22, 2017, 4:43 a.m.
On Tue, Feb 21, 2017 at 02:53:38PM +0300, Kirill Tkhai wrote:
> On 21.02.2017 08:45, Andrei Vagin wrote:
> > On Thu, Feb 16, 2017 at 03:07:19PM +0300, Kirill Tkhai wrote:
> >> 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.
> >>
> >> Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
> >> ---
> >>  criu/include/namespaces.h |   12 ++++++
> >>  criu/namespaces.c         |   87 +++++++++++++++++++++++++++++++++++++++++++++
> >>  2 files changed, 99 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 9e61c9481..c4ef52733 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,88 @@ 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) {
> >> +			pr_info("Can't get user_ns of %s %u, assuming NS_ROOT\n",
> >> +					nd->str, ns->id);
> > 
> > It is possible only if we dump only one userns.
> 
> Sure, and if we have several user_ns, we'll fail on NS_GET_PARENT made for one of them.

pls, add a comment here about this.

> 
> >> +			u_ns = NULL;
> >> +			if (root_ns_mask & CLONE_NEWUSER) {
> >> +				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 is zero here
> 
> Yeah, I'll fix that.
> 
> > 
> >> +				goto out;
> >> +			}
> >> +			ns->user_ns = NULL;
> >> +		}
> >> +	}
> >> +	ret = 0;
> >> +out:
> >> +	close(fd);
> >> +	return ret;
> >> +}
> >> +
> >>  static UsernsEntry userns_entry = USERNS_ENTRY__INIT;
> >>  #define INVALID_ID (~0U)
> >>  
> >>
> >> _______________________________________________
> >> CRIU mailing list
> >> CRIU@openvz.org
> >> https://lists.openvz.org/mailman/listinfo/criu
Kirill Tkhai Feb. 22, 2017, 8:53 a.m.
On 22.02.2017 07:43, Andrei Vagin wrote:
> On Tue, Feb 21, 2017 at 02:53:38PM +0300, Kirill Tkhai wrote:
>> On 21.02.2017 08:45, Andrei Vagin wrote:
>>> On Thu, Feb 16, 2017 at 03:07:19PM +0300, Kirill Tkhai wrote:
>>>> 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.
>>>>
>>>> Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
>>>> ---
>>>>  criu/include/namespaces.h |   12 ++++++
>>>>  criu/namespaces.c         |   87 +++++++++++++++++++++++++++++++++++++++++++++
>>>>  2 files changed, 99 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 9e61c9481..c4ef52733 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,88 @@ 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) {
>>>> +			pr_info("Can't get user_ns of %s %u, assuming NS_ROOT\n",
>>>> +					nd->str, ns->id);
>>>
>>> It is possible only if we dump only one userns.
>>
>> Sure, and if we have several user_ns, we'll fail on NS_GET_PARENT made for one of them.
> 
> pls, add a comment here about this.

OK

>>
>>>> +			u_ns = NULL;
>>>> +			if (root_ns_mask & CLONE_NEWUSER) {
>>>> +				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 is zero here
>>
>> Yeah, I'll fix that.
>>
>>>
>>>> +				goto out;
>>>> +			}
>>>> +			ns->user_ns = NULL;
>>>> +		}
>>>> +	}
>>>> +	ret = 0;
>>>> +out:
>>>> +	close(fd);
>>>> +	return ret;
>>>> +}
>>>> +
>>>>  static UsernsEntry userns_entry = USERNS_ENTRY__INIT;
>>>>  #define INVALID_ID (~0U)
>>>>  
>>>>
>>>> _______________________________________________
>>>> CRIU mailing list
>>>> CRIU@openvz.org
>>>> https://lists.openvz.org/mailman/listinfo/criu