]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
lxc-usernsexec: support easily mapping own uid 3177/head
authorSerge Hallyn <shallyn@cisco.com>
Fri, 1 Nov 2019 05:34:02 +0000 (00:34 -0500)
committerSerge Hallyn <shallyn@cisco.com>
Sat, 2 Nov 2019 13:28:51 +0000 (08:28 -0500)
Signed-off-by: Serge Hallyn <shallyn@cisco.com>
src/lxc/cmd/lxc_usernsexec.c

index 608001e8cdb941919a11865579d32c739dca0114..396a208be5e41d87d2c0a5c4606b6055e09fb7b3 100644 (file)
@@ -57,12 +57,13 @@ extern int lxc_log_fd;
 
 static void usage(const char *name)
 {
-       printf("usage: %s [-h] [-m <uid-maps>] -- [command [arg ..]]\n", name);
+       printf("usage: %s [-h] [-m <uid-maps>] [-s] -- [command [arg ..]]\n", name);
        printf("\n");
        printf("  -h            this message\n");
        printf("\n");
        printf("  -m <uid-maps> uid maps to use\n");
        printf("\n");
+       printf("  -s:           map self\n");
        printf("  uid-maps: [u|g|b]:ns_id:host_id:range\n");
        printf("            [u|g|b]: map user id, group id, or both\n");
        printf("            ns_id: the base id in the new namespace\n");
@@ -136,18 +137,40 @@ static int do_child(void *vargv)
 
 static struct lxc_list active_map;
 
+static int add_map_entry(long host_id, long ns_id, long range, int which)
+{
+       struct lxc_list *tmp = NULL;
+       struct id_map *newmap;
+
+       newmap = malloc(sizeof(*newmap));
+       if (!newmap)
+               return -1;
+
+       newmap->hostid = host_id;
+       newmap->nsid = ns_id;
+       newmap->range = range;
+       newmap->idtype = which;
+       tmp = malloc(sizeof(*tmp));
+       if (!tmp) {
+               free(newmap);
+               return -1;
+       }
+
+       tmp->elem = newmap;
+       lxc_list_add_tail(&active_map, tmp);
+       return 0;
+}
+
 /*
  * Given a string like "b:0:100000:10", map both uids and gids 0-10 to 100000
  * to 100010
  */
 static int parse_map(char *map)
 {
-       int i, ret;
+       int i, ret, idtype;
        long host_id, ns_id, range;
        char which;
-       struct id_map *newmap;
        char types[2] = {'u', 'g'};
-       struct lxc_list *tmp = NULL;
 
        if (!map)
                return -1;
@@ -163,27 +186,14 @@ static int parse_map(char *map)
                if (which != types[i] && which != 'b')
                        continue;
 
-               newmap = malloc(sizeof(*newmap));
-               if (!newmap)
-                       return -1;
-
-               newmap->hostid = host_id;
-               newmap->nsid = ns_id;
-               newmap->range = range;
-
                if (types[i] == 'u')
-                       newmap->idtype = ID_TYPE_UID;
+                       idtype = ID_TYPE_UID;
                else
-                       newmap->idtype = ID_TYPE_GID;
-
-               tmp = malloc(sizeof(*tmp));
-               if (!tmp) {
-                       free(newmap);
-                       return -1;
-               }
+                       idtype = ID_TYPE_GID;
 
-               tmp->elem = newmap;
-               lxc_list_add_tail(&active_map, tmp);
+               ret = add_map_entry(host_id, ns_id, range, idtype);
+               if (ret < 0)
+                       return ret;
        }
 
        return 0;
@@ -206,8 +216,6 @@ static int read_default_map(char *fnam, int which, char *user)
        unsigned long ul1, ul2;
        int ret = -1;
        size_t sz = 0;
-       struct lxc_list *tmp = NULL;
-       struct id_map *newmap = NULL;
 
        fin = fopen(fnam, "r");
        if (!fin)
@@ -237,26 +245,7 @@ static int read_default_map(char *fnam, int which, char *user)
                if (ret < 0)
                        break;
 
-               ret = -1;
-               newmap = malloc(sizeof(*newmap));
-               if (!newmap)
-                       break;
-
-               newmap->nsid = 0;
-               newmap->idtype = which;
-               newmap->hostid = ul1;
-               newmap->range = ul2;
-
-               tmp = malloc(sizeof(*tmp));
-               if (!tmp) {
-                       free(newmap);
-                       break;
-               }
-
-               tmp->elem = newmap;
-               lxc_list_add_tail(&active_map, tmp);
-
-               ret = 0;
+               ret = add_map_entry(ul1, 0, ul2, which);
                break;
        }
 
@@ -299,6 +288,42 @@ static int find_default_map(void)
        return 0;
 }
 
+static bool is_in_ns_range(long id, struct id_map *map)
+{
+       if (id < map->nsid)
+               return false;
+       if (id >= map->nsid + map->range)
+               return false;
+       return true;
+}
+
+static bool do_map_self(void)
+{
+       struct id_map *map;
+       long nsuid = 0, nsgid = 0;
+       struct lxc_list *tmp = NULL;
+       int ret;
+
+       lxc_list_for_each(tmp, &active_map) {
+               map = tmp->elem;
+               if (map->idtype == ID_TYPE_UID) {
+                       if (is_in_ns_range(nsuid, map))
+                               nsuid += map->range;
+               } else {
+                       if (is_in_ns_range(nsgid, map))
+                               nsgid += map->range;
+               }
+       }
+
+       ret = add_map_entry(getgid(), nsgid, 1, ID_TYPE_GID);
+       if (ret < 0)
+               return false;
+       ret = add_map_entry(getuid(), nsuid, 1, ID_TYPE_UID);
+       if (ret < 0)
+               return false;
+       return true;
+}
+
 int main(int argc, char *argv[])
 {
        int c, pid, ret, status;
@@ -308,6 +333,7 @@ int main(int argc, char *argv[])
        unsigned long flags = CLONE_NEWUSER | CLONE_NEWNS;
        char ttyname0[256] = {0}, ttyname1[256] = {0}, ttyname2[256] = {0};
        char *default_args[] = {"/bin/sh", NULL};
+       bool map_self = false;
 
        lxc_log_fd = STDERR_FILENO;
 
@@ -333,7 +359,7 @@ int main(int argc, char *argv[])
 
        lxc_list_init(&active_map);
 
-       while ((c = getopt(argc, argv, "m:h")) != EOF) {
+       while ((c = getopt(argc, argv, "m:hs")) != EOF) {
                switch (c) {
                case 'm':
                        ret = parse_map(optarg);
@@ -345,6 +371,9 @@ int main(int argc, char *argv[])
                case 'h':
                        usage(argv[0]);
                        _exit(EXIT_SUCCESS);
+               case 's':
+                       map_self = true;
+                       break;
                default:
                        usage(argv[0]);
                        _exit(EXIT_FAILURE);
@@ -359,6 +388,15 @@ int main(int argc, char *argv[])
                }
        }
 
+       // Do we want to support map-self with no other allocations?
+       // If so we should move this above the previous block.
+       if (map_self) {
+               if (!do_map_self()) {
+                       fprintf(stderr, "Failed mapping own uid\n");
+                       _exit(EXIT_FAILURE);
+               }
+       }
+
        argv = &argv[optind];
        argc = argc - optind;
        if (argc < 1)