Quoting TAMUKI Shoichi ([email protected]):
> Change chown_mapped_root() to map in both the root uid and gid, not
> just the uid, so as to work lxc-start with unprivileged containers on
> recent kernel.
> 
> Signed-off-by: TAMUKI Shoichi <[email protected]>
> Signed-off-by: KATOH Yasufumi <[email protected]>

Thank you for doing this!

Acked-by: Serge E. Hallyn <[email protected]>

> ---
> The patch has been revised due to amending the explanation of
> chown_mapped_root() a bit.  Please ignore the previous one.
> 
>  src/lxc/conf.c | 93 
> +++++++++++++++++++++++++++++++++++++++++++++-------------
>  1 file changed, 72 insertions(+), 21 deletions(-)
> 
> diff --git a/src/lxc/conf.c b/src/lxc/conf.c
> index c8b573a..df2f7cc 100644
> --- a/src/lxc/conf.c
> +++ b/src/lxc/conf.c
> @@ -3327,7 +3327,8 @@ int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
>  }
>  
>  /*
> - * return the host uid to which the container root is mapped in *val.
> + * return the host uid/gid to which the container root is mapped in
> + * *val.
>   * Return true if id was found, false otherwise.
>   */
>  bool get_mapped_rootid(struct lxc_conf *conf, enum idtype idtype,
> @@ -3338,7 +3339,7 @@ bool get_mapped_rootid(struct lxc_conf *conf, enum 
> idtype idtype,
>  
>       lxc_list_for_each(it, &conf->id_map) {
>               map = it->elem;
> -             if (map->idtype != ID_TYPE_UID)
> +             if (map->idtype != idtype)
>                       continue;
>               if (map->nsid != 0)
>                       continue;
> @@ -3492,15 +3493,17 @@ void lxc_delete_tty(struct lxc_tty_info *tty_info)
>  }
>  
>  /*
> - * chown_mapped_root: for an unprivileged user with uid X to chown a dir
> - * to subuid Y, he needs to run chown as root in a userns where
> - * nsid 0 is mapped to hostuid Y, and nsid Y is mapped to hostuid
> - * X.  That way, the container root is privileged with respect to
> - * hostuid X, allowing him to do the chown.
> + * chown_mapped_root: for an unprivileged user with uid/gid X to
> + * chown a dir to subuid/subgid Y, he needs to run chown as root
> + * in a userns where nsid 0 is mapped to hostuid/hostgid Y, and
> + * nsid Y is mapped to hostuid/hostgid X.  That way, the container
> + * root is privileged with respect to hostuid/hostgid X, allowing
> + * him to do the chown.
>   */
>  int chown_mapped_root(char *path, struct lxc_conf *conf)
>  {
> -     uid_t rootid;
> +     uid_t rootuid;
> +     gid_t rootgid;
>       pid_t pid;
>       unsigned long val;
>       char *chownpath = path;
> @@ -3509,7 +3512,12 @@ int chown_mapped_root(char *path, struct lxc_conf 
> *conf)
>               ERROR("No mapping for container root");
>               return -1;
>       }
> -     rootid = (uid_t) val;
> +     rootuid = (uid_t) val;
> +     if (!get_mapped_rootid(conf, ID_TYPE_GID, &val)) {
> +             ERROR("No mapping for container root");
> +             return -1;
> +     }
> +     rootgid = (gid_t) val;
>  
>       /*
>        * In case of overlay, we want only the writeable layer
> @@ -3530,14 +3538,14 @@ int chown_mapped_root(char *path, struct lxc_conf 
> *conf)
>       }
>       path = chownpath;
>       if (geteuid() == 0) {
> -             if (chown(path, rootid, -1) < 0) {
> +             if (chown(path, rootuid, rootgid) < 0) {
>                       ERROR("Error chowning %s", path);
>                       return -1;
>               }
>               return 0;
>       }
>  
> -     if (rootid == geteuid()) {
> +     if (rootuid == geteuid()) {
>               // nothing to do
>               INFO("%s: container root is our uid;  no need to chown" 
> ,__func__);
>               return 0;
> @@ -3549,13 +3557,31 @@ int chown_mapped_root(char *path, struct lxc_conf 
> *conf)
>               return -1;
>       }
>       if (!pid) {
> -             int hostuid = geteuid(), ret;
> -             char map1[100], map2[100], map3[100];
> -             char *args[] = {"lxc-usernsexec", "-m", map1, "-m", map2, "-m",
> -                              map3, "--", "chown", "0", path, NULL};
> +             int hostuid = geteuid(), hostgid = getegid(), ret;
> +             struct stat sb;
> +             char map1[100], map2[100], map3[100], map4[100], map5[100];
> +             char ugid[100];
> +             char *args1[] = { "lxc-usernsexec", "-m", map1, "-m", map2,
> +                             "-m", map3, "-m", map5,
> +                             "--", "chown", ugid, path, NULL };
> +             char *args2[] = { "lxc-usernsexec", "-m", map1, "-m", map2,
> +                             "-m", map3, "-m", map4, "-m", map5,
> +                             "--", "chown", ugid, path, NULL };
> +
> +             // save the current gid of "path"
> +             if (stat(path, &sb) < 0) {
> +                     ERROR("Error stat %s", path);
> +                     return -1;
> +             }
>  
> -             // "u:0:rootid:1"
> -             ret = snprintf(map1, 100, "u:0:%d:1", rootid);
> +             // a trick for chgrp the file that is not owned by oneself
> +             if (chown(path, -1, hostgid) < 0) {
> +                     ERROR("Error chgrp %s", path);
> +                     return -1;
> +             }
> +
> +             // "u:0:rootuid:1"
> +             ret = snprintf(map1, 100, "u:0:%d:1", rootuid);
>               if (ret < 0 || ret >= 100) {
>                       ERROR("Error uid printing map string");
>                       return -1;
> @@ -3568,14 +3594,39 @@ int chown_mapped_root(char *path, struct lxc_conf 
> *conf)
>                       return -1;
>               }
>  
> -             // "g:0:hostgid:1"
> -             ret = snprintf(map3, 100, "g:0:%d:1", getgid());
> +             // "g:0:rootgid:1"
> +             ret = snprintf(map3, 100, "g:0:%d:1", rootgid);
>               if (ret < 0 || ret >= 100) {
> -                     ERROR("Error uid printing map string");
> +                     ERROR("Error gid printing map string");
>                       return -1;
>               }
>  
> -             ret = execvp("lxc-usernsexec", args);
> +             // "g:pathgid:rootgid+pathgid:1"
> +             ret = snprintf(map4, 100, "g:%d:%d:1", sb.st_gid,
> +                             rootgid + sb.st_gid);
> +             if (ret < 0 || ret >= 100) {
> +                     ERROR("Error gid printing map string");
> +                     return -1;
> +             }
> +
> +             // "g:hostgid:hostgid:1"
> +             ret = snprintf(map5, 100, "g:%d:%d:1", hostgid, hostgid);
> +             if (ret < 0 || ret >= 100) {
> +                     ERROR("Error gid printing map string");
> +                     return -1;
> +             }
> +
> +             // "0:pathgid" (chown)
> +             ret = snprintf(ugid, 100, "0:%d", sb.st_gid);
> +             if (ret < 0 || ret >= 100) {
> +                     ERROR("Error owner printing format string for chown");
> +                     return -1;
> +             }
> +
> +             if (hostgid == sb.st_gid)
> +                     ret = execvp("lxc-usernsexec", args1);
> +             else
> +                     ret = execvp("lxc-usernsexec", args2);
>               SYSERROR("Failed executing usernsexec");
>               exit(1);
>       }
> -- 
> 1.9.0
> _______________________________________________
> lxc-devel mailing list
> [email protected]
> http://lists.linuxcontainers.org/listinfo/lxc-devel
_______________________________________________
lxc-devel mailing list
[email protected]
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to