]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
cgroups: use of /sys/kernel/cgroup/delegate file 2820/head
authorChristian Brauner <christian.brauner@ubuntu.com>
Fri, 1 Feb 2019 09:57:49 +0000 (10:57 +0100)
committerChristian Brauner <christian.brauner@ubuntu.com>
Fri, 1 Feb 2019 10:31:46 +0000 (11:31 +0100)
This file contains the files one needs to chown to successfully delegate
cgroup files to unprivileged users.

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/cgroups/cgfsng.c
src/lxc/cgroups/cgroup.c
src/lxc/cgroups/cgroup.h

index c4fc652523f2d0c46f588c2c6da7eb8d387ffbef..d359b67fcd5377abde8ebcdaef0322f8d480fbdf 100644 (file)
@@ -820,6 +820,7 @@ static struct hierarchy *add_hierarchy(struct hierarchy ***h, char **clist, char
        new->container_full_path = NULL;
        new->monitor_full_path = NULL;
        new->version = type;
+       new->cgroup2_chown = NULL;
 
        newentry = append_null_to_list((void ***)h);
        (*h)[newentry] = new;
@@ -1640,13 +1641,11 @@ static int chown_cgroup_wrapper(void *data)
                if (arg->hierarchies[i]->version != CGROUP2_SUPER_MAGIC)
                        continue;
 
-               fullpath = must_make_path(path, "cgroup.subtree_control", NULL);
-               (void)chowmod(fullpath, destuid, nsgid, 0664);
-               free(fullpath);
-
-               fullpath = must_make_path(path, "cgroup.threads", NULL);
-               (void)chowmod(fullpath, destuid, nsgid, 0664);
-               free(fullpath);
+               for (char **p = arg->hierarchies[i]->cgroup2_chown; p && *p; p++) {
+                       fullpath = must_make_path(path, *p, NULL);
+                       (void)chowmod(fullpath, destuid, nsgid, 0664);
+                       free(fullpath);
+               }
        }
 
        return 0;
@@ -2524,10 +2523,40 @@ static bool cgroup_use_wants_controllers(const struct cgroup_ops *ops,
        return true;
 }
 
+static void cg_unified_delegate(char ***delegate)
+{
+       char *tmp;
+       int idx;
+       char *standard[] = {"cgroup.subtree_control", "cgroup.threads", NULL};
+
+       tmp = read_file("/sys/kernel/cgroup/delegate");
+       if (!tmp) {
+               for (char **p = standard; p && *p; p++) {
+                       idx = append_null_to_list((void ***)delegate);
+                       (*delegate)[idx] = must_copy_string(*p);
+               }
+       } else {
+               char *token;
+               lxc_iterate_parts (token, tmp, " \t\n") {
+                       /*
+                        * We always need to chown this for both cgroup and
+                        * cgroup2.
+                        */
+                       if (strcmp(token, "cgroup.procs") == 0)
+                               continue;
+
+                       idx = append_null_to_list((void ***)delegate);
+                       (*delegate)[idx] = must_copy_string(token);
+               }
+               free(tmp);
+       }
+}
+
 /* At startup, parse_hierarchies finds all the info we need about cgroup
  * mountpoints and current cgroups, and stores it in @d.
  */
-static bool cg_hybrid_init(struct cgroup_ops *ops, bool relative)
+static bool cg_hybrid_init(struct cgroup_ops *ops, bool relative,
+                          bool unprivileged)
 {
        int ret;
        char *basecginfo;
@@ -2642,8 +2671,11 @@ static bool cg_hybrid_init(struct cgroup_ops *ops, bool relative)
                        goto next;
 
                new = add_hierarchy(&ops->hierarchies, controller_list, mountpoint, base_cgroup, type);
-               if (type == CGROUP2_SUPER_MAGIC && !ops->unified)
+               if (type == CGROUP2_SUPER_MAGIC && !ops->unified) {
+                       if (unprivileged)
+                               cg_unified_delegate(&new->cgroup2_chown);
                        ops->unified = new;
+               }
 
                continue;
 
@@ -2719,11 +2751,13 @@ cleanup_on_err:
        return copy;
 }
 
-static int cg_unified_init(struct cgroup_ops *ops, bool relative)
+static int cg_unified_init(struct cgroup_ops *ops, bool relative,
+                          bool unprivileged)
 {
        int ret;
-       char *mountpoint, *subtree_path;
+       char *mountpoint, *subtree_path, *tmp;
        char **delegatable;
+       struct hierarchy *new;
        char *base_cgroup = NULL;
 
        ret = cg_is_pure_unified();
@@ -2759,7 +2793,9 @@ static int cg_unified_init(struct cgroup_ops *ops, bool relative)
         * controllers per container.
         */
 
-       add_hierarchy(&ops->hierarchies, delegatable, mountpoint, base_cgroup, CGROUP2_SUPER_MAGIC);
+       new = add_hierarchy(&ops->hierarchies, delegatable, mountpoint, base_cgroup, CGROUP2_SUPER_MAGIC);
+       if (!unprivileged)
+               cg_unified_delegate(&new->cgroup2_chown);
 
        ops->cgroup_layout = CGROUP_LAYOUT_UNIFIED;
        return CGROUP2_SUPER_MAGIC;
@@ -2785,14 +2821,14 @@ static bool cg_init(struct cgroup_ops *ops, struct lxc_conf *conf)
                free(pin);
        }
 
-       ret = cg_unified_init(ops, relative);
+       ret = cg_unified_init(ops, relative, !lxc_list_empty(&conf->id_map));
        if (ret < 0)
                return false;
 
        if (ret == CGROUP2_SUPER_MAGIC)
                return true;
 
-       return cg_hybrid_init(ops, relative);
+       return cg_hybrid_init(ops, relative, !lxc_list_empty(&conf->id_map));
 }
 
 __cgfsng_ops static bool cgfsng_data_init(struct cgroup_ops *ops)
index f0d4e1eff16cac93d01f6571052fe0e9786e0466..bf92bf2985fb05c963c0c86e44737baceeff0b8d 100644 (file)
@@ -82,12 +82,16 @@ void cgroup_exit(struct cgroup_ops *ops)
        free(ops->container_cgroup);
 
        for (it = ops->hierarchies; it && *it; it++) {
-               char **ctrlr;
+               char **p;
 
-               for (ctrlr = (*it)->controllers; ctrlr && *ctrlr; ctrlr++)
-                       free(*ctrlr);
+               for (p = (*it)->controllers; p && *p; p++)
+                       free(*p);
                free((*it)->controllers);
 
+               for (p = (*it)->cgroup2_chown; p && *p; p++)
+                       free(*p);
+               free((*it)->cgroup2_chown);
+
                free((*it)->mountpoint);
                free((*it)->container_base_path);
                free((*it)->container_full_path);
index d4dcd506b223ce0844a5911ee15b77f16a203050..b5d4c42bc16865a34b1638ce90a9561df97c0f6a 100644 (file)
@@ -81,6 +81,11 @@ typedef enum {
  *   CGROUP2_SUPER_MAGIC.
  */
 struct hierarchy {
+       /*
+        * cgroup2 only: what files need to be chowned to delegate a cgroup to
+        * an unprivileged user.
+        */
+       char **cgroup2_chown;
        char **controllers;
        char *mountpoint;
        char *container_base_path;