]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
create_run_template: tell the template what caller's uid was mapped to
authorSerge Hallyn <serge.hallyn@ubuntu.com>
Fri, 1 Nov 2013 20:27:49 +0000 (15:27 -0500)
committerSerge Hallyn <serge.hallyn@ubuntu.com>
Wed, 6 Nov 2013 15:04:06 +0000 (09:04 -0600)
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 <serge.hallyn@ubuntu.com>
Acked-by: Stéphane Graber <stgraber@ubuntu.com>
src/lxc/conf.c
src/lxc/conf.h
src/lxc/lxccontainer.c
templates/lxc-ubuntu-cloud.in

index c131259386d9a9138a9569b17a96cc444e551c6f..1db2f3e39bef46ce0b79e17101193970c5056083 100644 (file)
@@ -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)
index 71399b9205bf85b059e6adabe0b7f12de2bca998..940d493719344e842c070b9f5784cfedcb0646f0 100644 (file)
@@ -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
index 7fa3d51904dbafd56c9323467e881143011a7d40..05e540587f4287d2f002470dc27597f06d778a57 100644 (file)
@@ -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;
                }
index 82a7f7484caa2e2355227473caad622d047482b3..41f1c70b95cbf1f267c0563da83f736319b7ce09 100644 (file)
@@ -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