[lxc-devel] [RFC 1/2] create_run_template: tell the template what caller's uid was mapped to

Stéphane Graber stgraber at ubuntu.com
Tue Nov 5 20:21:11 UTC 2013


On Tue, Nov 05, 2013 at 02:14:33PM -0600, Serge Hallyn wrote:
> conf.c/conf.h: have replaced bool hostid_is_mapped() with int mapped_hostid()
>    which returns the mapped uid for the caller's uid on the host, or -1 if
>    none
> 
> create_run_template: pass caller's uid into template.
> 
> lxc-ubuntu-cloud:
> 	1. accept --mapped-uid argument
> 	2. don't write to devices cgroup - not allowed.
> 	3. if running in userns, use $HOME/.cache
> 	4. chown cached files to the uid to which our caller was
> 	   mapped
> 	5. ignore /dev when extracting rootfs in a userns
> 
> Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>

There is just one info statement that looks a bit off a bit below, but
with that one dropped or properly indented:

Acked-by: Stéphane Graber <stgraber at ubuntu.com>

> ---
>  src/lxc/conf.c                |  6 +++---
>  src/lxc/conf.h                |  2 +-
>  src/lxc/lxccontainer.c        | 38 ++++++++++++++++++++++++++++++--------
>  templates/lxc-ubuntu-cloud.in | 25 +++++++++++++++++++++++--
>  4 files changed, 57 insertions(+), 14 deletions(-)
> 
> diff --git a/src/lxc/conf.c b/src/lxc/conf.c
> index 2a47e77..afdaa14 100644
> --- a/src/lxc/conf.c
> +++ b/src/lxc/conf.c
> @@ -2912,7 +2912,7 @@ uid_t get_mapped_rootid(struct lxc_conf *conf)
>  	return (uid_t)-1;
>  }
>  
> -bool hostid_is_mapped(int id, struct lxc_conf *conf)
> +int mapped_hostid(int id, struct lxc_conf *conf)
>  {
>  	struct lxc_list *it;
>  	struct id_map *map;
> @@ -2921,9 +2921,9 @@ bool hostid_is_mapped(int id, struct lxc_conf *conf)
>  		if (map->idtype != ID_TYPE_UID)
>  			continue;
>  		if (id >= map->hostid && id < map->hostid + map->range)
> -			return true;
> +			return (id - map->hostid) + map->nsid;
>  	}
> -	return false;
> +	return -1;
>  }
>  
>  int find_unmapped_nsuid(struct lxc_conf *conf)
> diff --git a/src/lxc/conf.h b/src/lxc/conf.h
> index 71399b9..940d493 100644
> --- a/src/lxc/conf.h
> +++ b/src/lxc/conf.h
> @@ -362,7 +362,7 @@ extern void lxc_rename_phys_nics_on_shutdown(struct lxc_conf *conf);
>  
>  extern uid_t get_mapped_rootid(struct lxc_conf *conf);
>  extern int find_unmapped_nsuid(struct lxc_conf *conf);
> -extern bool hostid_is_mapped(int id, struct lxc_conf *conf);
> +extern int mapped_hostid(int id, struct lxc_conf *conf);
>  extern int chown_mapped_root(char *path, struct lxc_conf *conf);
>  extern int ttys_shift_ids(struct lxc_conf *c);
>  #endif
> diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
> index 946133d..594a96d 100644
> --- a/src/lxc/lxccontainer.c
> +++ b/src/lxc/lxccontainer.c
> @@ -916,20 +916,28 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool quiet
>  		 * If we're running the template in a mapped userns, then
>  		 * we prepend the template command with:
>  		 * lxc-usernsexec <-m map1> ... <-m mapn> --
> +		 * and we append "--mapped-uid x", where x is the mapped uid
> +		 * for our geteuid()
>  		 */
>  		if (geteuid() != 0 && !lxc_list_empty(&conf->id_map)) {
>  			int n2args = 1;
> +			char txtuid[20];
>  			char **n2 = malloc(n2args * sizeof(*n2));
>  			struct lxc_list *it;
>  			struct id_map *map;
>  
> +			if (!n2) {
> +				SYSERROR("out of memory");
> +				exit(1);
> +			}
>  			newargv[0] = tpath;
>  			tpath = "lxc-usernsexec";
>  			n2[0] = "lxc-usernsexec";
>  			lxc_list_for_each(it, &conf->id_map) {
>  				map = it->elem;
>  				n2args += 2;
> -				n2 = realloc(n2, n2args * sizeof(*n2));
> +				n2 = realloc(n2, n2args * sizeof(char *));
> +INFO("allocated %d items to n2", n2args);

^ what happened with indentation here?

>  				if (!n2)
>  					exit(1);
>  				n2[n2args-2] = "-m";
> @@ -942,15 +950,15 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool quiet
>  				if (ret < 0 || ret >= 200)
>  					exit(1);
>  			}
> -			bool hostid_mapped = hostid_is_mapped(geteuid(), conf);
> -			int extraargs = hostid_mapped ?  1 : 3;
> -			n2 = realloc(n2, (nargs + n2args + extraargs) * sizeof(*n2));
> +			int hostid_mapped = mapped_hostid(geteuid(), conf);
> +			int extraargs = hostid_mapped >= 0 ?  1 : 3;
> +			n2 = realloc(n2, (nargs + n2args + extraargs) * sizeof(char *));
>  			if (!n2)
>  				exit(1);
> -			if (!hostid_mapped) {
> -				int free_id = find_unmapped_nsuid(conf);
> +			if (hostid_mapped < 0) {
> +				hostid_mapped = find_unmapped_nsuid(conf);
>  				n2[n2args++] = "-m";
> -				if (free_id < 0) {
> +				if (hostid_mapped < 0) {
>  					ERROR("Could not find free uid to map");
>  					exit(1);
>  				}
> @@ -960,7 +968,7 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool quiet
>  					exit(1);
>  				}
>  				ret = snprintf(n2[n2args-1], 200, "u:%d:%d:1",
> -					free_id, geteuid());
> +					hostid_mapped, geteuid());
>  				if (ret < 0 || ret >= 200) {
>  					ERROR("string too long");
>  					exit(1);
> @@ -969,6 +977,20 @@ static bool create_run_template(struct lxc_container *c, char *tpath, bool quiet
>  			n2[n2args++] = "--";
>  			for (i = 0; i < nargs; i++)
>  				n2[i + n2args] = newargv[i];
> +			n2args += nargs;
> +			// Finally add "--mapped-uid $uid" to tell template what to chown
> +			// cached images to
> +			n2args += 2;
> +			n2 = realloc(n2, n2args * sizeof(char *));
> +			if (!n2) {
> +				SYSERROR("out of memory");
> +				exit(1);
> +			}
> +			// note n2[n2args-1] is NULL
> +			n2[n2args-3] = "--mapped-uid";
> +			snprintf(txtuid, 20, "%d", hostid_mapped);
> +			n2[n2args-2] = txtuid;
> +			n2[n2args-1] = NULL;
>  			free(newargv);
>  			newargv = n2;
>  		}
> diff --git a/templates/lxc-ubuntu-cloud.in b/templates/lxc-ubuntu-cloud.in
> index 82a7f74..41f1c70 100644
> --- a/templates/lxc-ubuntu-cloud.in
> +++ b/templates/lxc-ubuntu-cloud.in
> @@ -80,7 +80,11 @@ lxc.cap.drop = sys_module mac_admin mac_override sys_time
>  #lxc.hook.mount = /usr/share/lxc/hooks/mountcgroups
>  
>  lxc.hook.clone = ${CLONE_HOOK_FN}
> +EOF
>  
> +    # can't write to devices.deny without CAP_SYS_ADMIN in init-user-ns
> +    if [ $in_userns -ne 1 ]; then
> +	    cat <<EOF >> $path/config
>  lxc.cgroup.devices.deny = a
>  # Allow any mknod (but not using the node)
>  lxc.cgroup.devices.allow = c *:* m
> @@ -109,6 +113,7 @@ lxc.cgroup.devices.allow = c 10:228 rwm
>  # kvm
>  lxc.cgroup.devices.allow = c 10:232 rwm
>  EOF
> +    fi
>  
>      cat <<EOF > $path/fstab
>  proc            proc         proc    nodev,noexec,nosuid 0 0
> @@ -123,6 +128,7 @@ EOF
>      # that in the kernel, but not right now.  So let's just bind
>      # mount the files from the host.
>      if [ $in_userns -eq 1 ]; then
> +        mkdir -p $rootfs/dev/pts
>          for dev in null tty urandom console; do
>              touch $rootfs/dev/$dev
>              echo "/dev/$dev dev/$dev    none bind 0 0" >> $path/fstab
> @@ -161,13 +167,14 @@ EOF
>      return 0
>  }
>  
> -options=$(getopt -o a:hp:r:n:Fi:CLS:T:ds:u: -l arch:,help,rootfs:,path:,release:,name:,flush-cache,hostid:,auth-key:,cloud,no_locales,tarball:,debug,stream:,userdata: -- "$@")
> +options=$(getopt -o a:hp:r:n:Fi:CLS:T:ds:u: -l arch:,help,rootfs:,path:,release:,name:,flush-cache,hostid:,auth-key:,cloud,no_locales,tarball:,debug,stream:,userdata:,mapped-uid: -- "$@")
>  if [ $? -ne 0 ]; then
>      usage $(basename $0)
>      exit 1
>  fi
>  eval set -- "$options"
>  
> +mapped_uid=-1
>  # default release is precise, or the systems release if recognized
>  release=precise
>  if [ -f /etc/lsb-release ]; then
> @@ -224,11 +231,13 @@ do
>      -u|--userdata)     cloneargs[${#cloneargs[@]}]="--userdata=$2"; shift 2;;
>      -C|--cloud)        cloneargs[${#cloneargs[@]}]="--cloud"; shift 1;;
>      -S|--auth-key)     cloneargs[${#cloneargs[@]}]="--auth-key=$2"; shift 2;;
> +    --mapped-uid)      mapped_uid=$2; shift 2;;
>      --)                shift 1; break ;;
>          *)              break ;;
>      esac
>  done
>  
> +echo "mapped_uid is .$mapped_uid."
>  cloneargs=( "--name=$name" "${cloneargs[@]}" )
>  
>  if [ $debug -eq 1 ]; then
> @@ -296,6 +305,8 @@ type wget
>  # determine the url, tarball, and directory names
>  # download if needed
>  cache="$STATE_DIR/cache/lxc/cloud-$release"
> +STATE_DIR="$HOME/.cache/lxc/"
> +cache="$HOME/.cache/lxc/cloud-$release"
>  
>  mkdir -p $cache
>  
> @@ -371,7 +382,11 @@ do_extract_rootfs() {
>      echo "Extracting container rootfs"
>      mkdir -p $rootfs
>      cd $rootfs
> -    tar --numeric-owner -xpzf "$cache/$filename"
> +    if [ $in_userns -eq 1 ]; then
> +        tar --anchored --exclude="dev/*" --numeric-owner -xpzf "$cache/$filename"
> +    else
> +        tar --numeric-owner -xpzf "$cache/$filename"
> +    fi
>  }
>  
>  if [ -n "$tarball" ]; then
> @@ -388,6 +403,12 @@ copy_configuration $path $rootfs $name $arch $release
>  
>  "$CLONE_HOOK_FN" "${cloneargs[@]}" "$rootfs"
>  
> +if [ $mapped_uid -ne -1 ]; then
> +	chown $mapped_uid $path/config
> +	chown -R $mapped_uid $STATE_DIR
> +	chown -R $mapped_uid $cache
> +fi
> +
>  echo "Container $name created."
>  exit 0
>  
> -- 
> 1.8.4.2
> 
> 
> ------------------------------------------------------------------------------
> November Webinars for C, C++, Fortran Developers
> Accelerate application performance with scalable programming models. Explore
> techniques for threading, error checking, porting, and tuning. Get the most 
> from the latest Intel processors and coprocessors. See abstracts and register
> http://pubads.g.doubleclick.net/gampad/clk?id=60136231&iu=/4140/ostg.clktrk
> _______________________________________________
> Lxc-devel mailing list
> Lxc-devel at lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/lxc-devel

-- 
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20131105/b04bc979/attachment.pgp>


More information about the lxc-devel mailing list