[lxc-devel] [PATCH] Fix unprivileged containers started by root

Dwight Engen dwight.engen at oracle.com
Wed Feb 26 20:55:56 UTC 2014


On Wed, 26 Feb 2014 14:55:57 -0500
Stéphane Graber <stgraber at ubuntu.com> wrote:

> Hi Dwight,
> 
> Serge suggested that you may have been relying on the previous
> behavior, will that change be a problem for you?
> 
> Do you think this is reasonable?
> 
> Stéphane

Hey Stéphane, yeah I was running unprivileged containers and using the
lxc writing the mapping functionality. Up till this change we could do
manual management of uid ranges and not *have* to have new[ug]idmap. At
least I hadn't hit the other two cases where it was needed (running a
template in a mapped userns and chown_mapped_root()). I do get that it
would be nice to just rely on the presence of new[ug]id map, especially
to avoid range overlap.

RHEL7/OL7/Fedora rawhide still only ship shadow 4.1.x so that what is a
bit of a problem right now. Not that its hard to build a 4.2 shadow
rpm, I've got one locally and I think Mike was building one too. Do we
know where other distros are as far as updating to the newest shadow? I
guess it just comes down to if we want to say that your distro must
have the new shadow if you want to use userns containers.

> On Wed, Feb 26, 2014 at 02:53:04PM -0500, Stéphane Graber wrote:
> > This change makes it possible to create unprivileged containers as
> > root. They will be stored in the usual system wide location, use
> > the usual system wide cache but will be running using a uid/gid map.
> > 
> > To make things consistent as well as avoid potential range
> > conflicts, I'm removing the code that was directly writing the
> > uid/gid ranges and instead force all unprivileged containers
> > through newuidmap/newgidmap. This means you need to grant uid/gid
> > ranges to root just as you would for a normal user.
> > 
> > bdev and network restrictions however don't apply to those
> > containers, so you don't need to add lxc-usernic entries for root.
> > 
> > This essentially requires anyone wanting to run unprivileged
> > containers to have newuidmap and newgidmap on their system, those
> > two are provided by a very recent version of shadow.
> > 
> > Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
> > ---
> >  src/lxc/conf.c         | 56
> > ++++++++++----------------------------------------
> > src/lxc/lxccontainer.c |  6 +++--- 2 files changed, 14
> > insertions(+), 48 deletions(-)
> > 
> > diff --git a/src/lxc/conf.c b/src/lxc/conf.c
> > index fc39897..2a9b672 100644
> > --- a/src/lxc/conf.c
> > +++ b/src/lxc/conf.c
> > @@ -3132,32 +3132,6 @@ int lxc_assign_network(struct lxc_list
> > *network, pid_t pid) return 0;
> >  }
> >  
> > -static int write_id_mapping(enum idtype idtype, pid_t pid, const
> > char *buf,
> > -			    size_t buf_size)
> > -{
> > -	char path[PATH_MAX];
> > -	int ret, closeret;
> > -	FILE *f;
> > -
> > -	ret = snprintf(path, PATH_MAX, "/proc/%d/%cid_map", pid,
> > idtype == ID_TYPE_UID ? 'u' : 'g');
> > -	if (ret < 0 || ret >= PATH_MAX) {
> > -		fprintf(stderr, "%s: path name too long\n",
> > __func__);
> > -		return -E2BIG;
> > -	}
> > -	f = fopen(path, "w");
> > -	if (!f) {
> > -		perror("open");
> > -		return -EINVAL;
> > -	}
> > -	ret = fwrite(buf, buf_size, 1, f);
> > -	if (ret < 0)
> > -		SYSERROR("writing id mapping");
> > -	closeret = fclose(f);
> > -	if (closeret)
> > -		SYSERROR("writing id mapping");
> > -	return ret < 0 ? ret : closeret;
> > -}
> > -
> >  int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
> >  {
> >  	struct lxc_list *iterator;
> > @@ -3165,7 +3139,6 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t
> > pid) int ret = 0;
> >  	enum idtype type;
> >  	char *buf = NULL, *pos;
> > -	int am_root = (getuid() == 0);
> >  
> >  	for(type = ID_TYPE_UID; type <= ID_TYPE_GID; type++) {
> >  		int left, fill;
> > @@ -3176,10 +3149,9 @@ int lxc_map_ids(struct lxc_list *idmap,
> > pid_t pid) return -ENOMEM;
> >  		}
> >  		pos = buf;
> > -		if (!am_root)
> > -			pos += sprintf(buf, "new%cidmap %d",
> > -				type == ID_TYPE_UID ? 'u' : 'g',
> > -				pid);
> > +		pos += sprintf(buf, "new%cidmap %d",
> > +			type == ID_TYPE_UID ? 'u' : 'g',
> > +			pid);
> >  
> >  		lxc_list_for_each(iterator, idmap) {
> >  			/* The kernel only takes <= 4k for writes
> > to /proc/<nr>/[ug]id_map */ @@ -3189,10 +3161,8 @@ int
> > lxc_map_ids(struct lxc_list *idmap, pid_t pid) 
> >  			had_entry = 1;
> >  			left = 4096 - (pos - buf);
> > -			fill = snprintf(pos, left, "%s%lu %lu
> > %lu%s",
> > -					am_root ? "" : " ",
> > -					map->nsid, map->hostid,
> > map->range,
> > -					am_root ? "\n" : "");
> > +			fill = snprintf(pos, left, " %lu %lu %lu ",
> > +					map->nsid, map->hostid,
> > map->range); if (fill <= 0 || fill >= left)
> >  				SYSERROR("snprintf failed, too
> > many mappings"); pos += fill;
> > @@ -3200,16 +3170,12 @@ int lxc_map_ids(struct lxc_list *idmap,
> > pid_t pid) if (!had_entry)
> >  			continue;
> >  
> > -		if (am_root) {
> > -			ret = write_id_mapping(type, pid, buf,
> > pos-buf);
> > -		} else {
> > -			left = 4096 - (pos - buf);
> > -			fill = snprintf(pos, left, "\n");
> > -			if (fill <= 0 || fill >= left)
> > -				SYSERROR("snprintf failed, too
> > many mappings");
> > -			pos += fill;
> > -			ret = system(buf);
> > -		}
> > +		left = 4096 - (pos - buf);
> > +		fill = snprintf(pos, left, "\n");
> > +		if (fill <= 0 || fill >= left)
> > +			SYSERROR("snprintf failed, too many
> > mappings");
> > +		pos += fill;
> > +		ret = system(buf);
> >  
> >  		if (ret)
> >  			break;
> > diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
> > index 0427791..d9aa973 100644
> > --- a/src/lxc/lxccontainer.c
> > +++ b/src/lxc/lxccontainer.c
> > @@ -806,7 +806,7 @@ static struct bdev *do_bdev_create(struct
> > lxc_container *c, const char *type, /* if we are not root, chown
> > the rootfs dir to root in the
> >  	 * target uidmap */
> >  
> > -	if (geteuid() != 0) {
> > +	if (geteuid() != 0 || (c->lxc_conf
> > && !lxc_list_empty(&c->lxc_conf->id_map))) { if
> > (chown_mapped_root(bdev->dest, c->lxc_conf) < 0) { ERROR("Error
> > chowning %s to container root", bdev->dest); bdev_put(bdev);
> > @@ -992,7 +992,7 @@ static bool create_run_template(struct
> > lxc_container *c, char *tpath, bool quiet
> >  		 * and we append "--mapped-uid x", where x is the
> > mapped uid
> >  		 * for our geteuid()
> >  		 */
> > -		if (geteuid() != 0
> > && !lxc_list_empty(&conf->id_map)) {
> > +		if (!lxc_list_empty(&conf->id_map)) {
> >  			int n2args = 1;
> >  			char txtuid[20];
> >  			char txtgid[20];
> > @@ -1450,7 +1450,7 @@ static inline bool enter_to_ns(struct
> > lxc_container *c) { init_pid = c->init_pid(c);
> >  
> >  	/* Switch to new userns */
> > -	if (geteuid() && access("/proc/self/ns/user", F_OK) == 0) {
> > +	if ((geteuid() != 0 || (c->lxc_conf
> > && !lxc_list_empty(&c->lxc_conf->id_map))) &&
> > access("/proc/self/ns/user", F_OK) == 0) { ret =
> > snprintf(new_userns_path, MAXPATHLEN, "/proc/%d/ns/user",
> > init_pid); if (ret < 0 || ret >= MAXPATHLEN) goto out; -- 
> > 1.9.0
> > 
> 



More information about the lxc-devel mailing list