[CRIU] [PATCH 08/14] dump: dump user namespaces

Andrew Vagin avagin at parallels.com
Wed Oct 15 00:31:36 PDT 2014


On Tue, Oct 14, 2014 at 07:18:07PM +0400, Pavel Emelyanov wrote:
> On 10/14/2014 03:38 PM, Andrey Vagin wrote:
> > For that we need to save per-namespace mappings of user and group IDs.
> > 
> > And all id-s for tasks and files are saved from the target user
> > namespace.
> > 
> > Signed-off-by: Andrey Vagin <avagin at openvz.org>
> > ---
> >  cr-dump.c            |  11 ++++
> >  include/namespaces.h |   3 ++
> >  namespaces.c         | 140 +++++++++++++++++++++++++++++++++++++++++++++++----
> >  3 files changed, 145 insertions(+), 9 deletions(-)
> > 
> > diff --git a/cr-dump.c b/cr-dump.c
> > index ed7de5f..3959807 100644
> > --- a/cr-dump.c
> > +++ b/cr-dump.c
> > @@ -1842,6 +1842,16 @@ int cr_dump_tasks(pid_t pid)
> >  	if (collect_namespaces(true) < 0)
> >  		goto err;
> >  
> > +	if (root_ns_mask & CLONE_NEWUSER) {
> > +		/*
> > +		 * User namespace is dumped before files to get uid and gid
> > +		 * mappings, which are used for convirting local id-s to
> > +		 * userns id-s (userns_uid(), userns_gid())
> > +		 */
> > +		if (dump_user_ns(root_item->pid.real, root_item->ids->user_ns_id))
> 
> This heavily uses the fact, that nsid generator makes sure there's only
> one userns. What are the problems to support multiple user namespaces
> from the very beginning?

Userns is hierarchical. It isn't so easy to find who is parent or child.
We support nested mount namespaces. Each mount namespace is owned by
userns. Now an owner is not shown for a mount namespace.

I think here are a number of other issues.

> 
> > +			goto err;
> > +	}
> > +
> >  	glob_imgset = cr_glob_imgset_open(O_DUMP);
> >  	if (!glob_imgset)
> >  		goto err;
> > @@ -1947,6 +1957,7 @@ err:
> >  	free_file_locks();
> >  	free_link_remaps();
> >  	free_aufs_branches();
> > +	free_userns_maps();
> >  
> >  	close_service_fd(CR_PROC_FD_OFF);
> >  
> > diff --git a/include/namespaces.h b/include/namespaces.h
> > index d2f3e76..5b1c6fb 100644
> > --- a/include/namespaces.h
> > +++ b/include/namespaces.h
> > @@ -62,7 +62,10 @@ extern struct ns_id *rst_new_ns_id(unsigned int id, pid_t pid, struct ns_desc *n
> >  extern int rst_add_ns_id(unsigned int id, pid_t pid, struct ns_desc *nd);
> >  extern struct ns_id *lookup_ns_by_id(unsigned int id, struct ns_desc *nd);
> >  
> > +extern int prepare_userns(struct pstree_item *item);
> >  extern int userns_uid(int uid);
> >  extern int userns_gid(int gid);
> > +extern int dump_user_ns(pid_t pid, int ns_id);
> > +extern void free_userns_maps(void);
> >  
> >  #endif /* __CR_NS_H__ */
> > diff --git a/namespaces.c b/namespaces.c
> > index 918729b..7bc4ced 100644
> > --- a/namespaces.c
> > +++ b/namespaces.c
> > @@ -15,6 +15,7 @@
> >  
> >  #include "protobuf.h"
> >  #include "protobuf/ns.pb-c.h"
> > +#include "protobuf/userns.pb-c.h"
> >  
> >  static struct ns_desc *ns_desc_array[] = {
> >  	&net_ns_desc,
> > @@ -438,27 +439,149 @@ int dump_task_ns_ids(struct pstree_item *item)
> >  	return 0;
> >  }
> >  
> > -static int userns_id(int id)
> > +static UsernsEntry userns_entry = USERNS_ENTRY__INIT;
> > +
> > +static int userns_id(int id, UidGidExtent **map, int n)
> >  {
> > -	return id;
> > +	int i;
> > +
> > +	if (!(root_ns_mask & CLONE_NEWUSER))
> > +		return id;
> > +
> > +	for (i = 0; i < n; i++) {
> > +		if (map[i]->lower_first <= id &&
> > +		    map[i]->lower_first + map[i]->count > id)
> > +			return map[i]->first + (id - map[i]->lower_first);
> > +	}
> > +
> > +	return -1;
> >  }
> >  
> >  int userns_uid(int uid)
> >  {
> > -	return userns_id(uid);
> > +	UsernsEntry *e = &userns_entry;
> > +	return userns_id(uid, e->uid_map, e->n_uid_map);
> >  }
> >  
> >  int userns_gid(int gid)
> >  {
> > -	return userns_id(gid);
> > +	UsernsEntry *e = &userns_entry;
> > +	return userns_id(gid, e->gid_map, e->n_gid_map);
> >  }
> >  
> > -static int dump_user_ns(pid_t pid, int ns_id)
> > +static int parse_id_map(pid_t pid, char *name, UidGidExtent ***pb_exts)
> >  {
> > -	pr_err("User namesapces are not supported yet\n");
> > +	UidGidExtent *extents = NULL;
> > +	int len = 0, size = 0, ret, i;
> > +	FILE *f;
> > +
> > +	f = fopen_proc(pid, "%s", name);
> > +	if (f == NULL)
> > +		return -1;
> > +
> > +	ret = -1;
> > +	while (1) {
> > +		UidGidExtent *ext;
> > +
> > +		if (len == size) {
> > +			UidGidExtent *t;
> > +
> > +			size = size * 2 + 1;
> > +			t = xrealloc(extents, size * sizeof(UidGidExtent));
> > +			if (t == NULL)
> > +				break;
> > +			extents = t;
> > +		}
> > +
> > +		ext = &extents[len];
> > +
> > +		uid_gid_extent__init(ext);
> > +		ret = fscanf(f, "%d %d %d", &ext->first,
> > +				&ext->lower_first, &ext->count);
> > +		if (ret != 3) {
> > +			if (errno != 0) {
> > +				pr_perror("Unable to parse extents");
> > +				ret = -1;
> > +			} else
> > +				ret = 0;
> > +			break;
> > +		}
> > +		pr_info("id_map: %d %d %d\n", ext->first, ext->lower_first, ext->count);
> > +		len++;
> > +	}
> > +
> > +	fclose(f);
> > +
> > +	if (ret)
> > +		goto err;
> > +
> > +	if (len) {
> > +		*pb_exts = xmalloc(sizeof(UidGidExtent *) * len);
> > +		if (*pb_exts == NULL)
> > +			goto err;
> > +
> > +		for (i = 0; i < len; i++)
> > +			(*pb_exts)[i] = &extents[i];
> > +	} else {
> > +		xfree(extents);
> > +		*pb_exts = NULL;
> > +	}
> > +
> > +	return len;
> > +err:
> > +	xfree(extents);
> >  	return -1;
> >  }
> >  
> > +int dump_user_ns(pid_t pid, int ns_id)
> > +{
> > +	int ret, exit_code = -1;
> > +	UsernsEntry *e = &userns_entry;
> > +	struct cr_img *img;
> > +
> > +	ret = parse_id_map(pid, "uid_map", &e->uid_map);
> > +	if (ret < 0)
> > +		goto err;
> > +	e->n_uid_map = ret;
> > +
> > +	ret = parse_id_map(pid, "gid_map", &e->gid_map);
> > +	if (ret < 0)
> > +		goto err;
> > +	e->n_gid_map = ret;
> > +
> > +	img = open_image(CR_FD_USERNS, O_DUMP, ns_id);
> > +	if (!img)
> > +		goto err;
> > +	ret = pb_write_one(img, e, PB_USERNS);
> > +	close_image(img);
> > +	if (ret < 0)
> > +		goto err;
> > +
> > +	return 0;
> > +err:
> > +	if (e->uid_map) {
> > +		xfree(e->uid_map[0]);
> > +		xfree(e->uid_map);
> > +	}
> > +	if (e->gid_map) {
> > +		xfree(e->gid_map[0]);
> > +		xfree(e->gid_map);
> > +	}
> > +	return exit_code;
> > +}
> > +
> > +void free_userns_maps()
> > +{
> > +	if (userns_entry.n_uid_map > 0) {
> > +		xfree(userns_entry.uid_map[0]);
> > +		xfree(userns_entry.uid_map);
> > +	}
> > +	if (userns_entry.n_gid_map > 0) {
> > +		xfree(userns_entry.gid_map[0]);
> > +		xfree(userns_entry.gid_map);
> > +	}
> > +}
> > +
> >  static int do_dump_namespaces(struct ns_id *ns)
> >  {
> >  	int ret;
> > @@ -484,9 +607,8 @@ static int do_dump_namespaces(struct ns_id *ns)
> >  		ret = dump_net_ns(ns->id);
> >  		break;
> >  	case CLONE_NEWUSER:
> > -		pr_info("Dump USER namespace info %d via %d\n",
> > -				ns->id, ns->pid);
> > -		ret = dump_user_ns(ns->pid, ns->id);
> > +		/* userns is dumped before dumping tasks */
> > +		ret = 0;
> >  		break;
> >  	default:
> >  		pr_err("Unknown namespace flag %x", ns->nd->cflag);
> > 
> 


More information about the CRIU mailing list