From: Serge Hallyn Date: Fri, 1 Nov 2013 20:27:49 +0000 (-0500) Subject: create_run_template: tell the template what caller's uid was mapped to X-Git-Tag: lxc-1.0.0.alpha3~19 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=57d116ab501594c2e50ab45f1cf2fae48c5eab09;p=thirdparty%2Flxc.git create_run_template: tell the template what caller's uid was mapped to 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 Changelog: nov 5: remove debugging INFO line. Signed-off-by: Serge Hallyn Acked-by: Stéphane Graber --- diff --git a/src/lxc/conf.c b/src/lxc/conf.c index c13125938..1db2f3e39 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 71399b920..940d49371 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 7fa3d5190..05e540587 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -917,20 +917,27 @@ 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 *)); if (!n2) exit(1); n2[n2args-2] = "-m"; @@ -943,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); } @@ -961,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); @@ -970,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 82a7f7484..41f1c70b9 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 <> $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 < $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