]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
cgroups: enable container without CAP_SYS_ADMIN
authorChristian Brauner <christian.brauner@ubuntu.com>
Mon, 30 Oct 2017 13:16:46 +0000 (14:16 +0100)
committerChristian Brauner <christian.brauner@ubuntu.com>
Thu, 9 Nov 2017 00:18:16 +0000 (01:18 +0100)
In case cgroup namespaces are supported but we do not have CAP_SYS_ADMIN we
need to mount cgroups for the container. This patch enables both privileged and
unprivileged containers without CAP_SYS_ADMIN.

Closes #1737.

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

index 066a93a4c314eddfd60b5751d95ff191c931a7b6..f4bcc34ffbfa72acc07d13a85f22a53a6489c6e5 100644 (file)
@@ -1418,11 +1418,12 @@ static bool cgroupfs_mount_cgroup(void *hdata, const char *root, int type)
        struct cgfs_data *cgfs_d;
        struct cgroup_process_info *info, *base_info;
        int r, saved_errno = 0;
+       struct lxc_handler *handler = hdata;
 
        if (cgns_supported())
                return true;
 
-       cgfs_d = hdata;
+       cgfs_d = handler->cgroup_data;
        if (!cgfs_d)
                return false;
        base_info = cgfs_d->info;
index e1a3a064da7dc627ce1b9070597bf0d9c547d172..f422f530374d421e64fe0d1be9a8a7929e222d60 100644 (file)
 #include <unistd.h>
 #include <sys/types.h>
 
+#include <linux/types.h>
+#include <linux/kdev_t.h>
+
+#include "caps.h"
 #include "cgroup.h"
 #include "cgroup_utils.h"
 #include "commands.h"
@@ -1587,17 +1591,49 @@ do_secondstage_mounts_if_needed(int type, struct hierarchy *h,
        return 0;
 }
 
+static int mount_cgroup_cgns_supported(struct hierarchy *h, const char *controllerpath)
+{
+        int ret;
+        char *controllers = NULL;
+        char *type = "cgroup2";
+
+       if (!h->is_cgroup_v2) {
+               controllers = lxc_string_join(",", (const char **)h->controllers, false);
+               if (!controllers)
+                       return -ENOMEM;
+               type = "cgroup";
+       }
+
+       ret = mount("cgroup", controllerpath, type, MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RELATIME, controllers);
+       free(controllers);
+       if (ret < 0) {
+               SYSERROR("Failed to mount %s with cgroup filesystem type %s", controllerpath, type);
+               return -1;
+       }
+
+       DEBUG("Mounted %s with cgroup filesystem type %s", controllerpath, type);
+       return 0;
+}
+
 static bool cgfsng_mount(void *hdata, const char *root, int type)
 {
-       struct cgfsng_handler_data *d = hdata;
+       int i;
        char *tmpfspath = NULL;
        bool retval = false;
-       int i;
+       struct lxc_handler *handler = hdata;
+       struct cgfsng_handler_data *d = handler->cgroup_data;
+       bool has_cgns = false, has_sys_admin = true;
 
        if ((type & LXC_AUTO_CGROUP_MASK) == 0)
                return true;
 
-       if (cgns_supported())
+       has_cgns = cgns_supported();
+       if (!lxc_list_empty(&handler->conf->keepcaps))
+               has_sys_admin = in_caplist(CAP_SYS_ADMIN, &handler->conf->keepcaps);
+       else
+               has_sys_admin = !in_caplist(CAP_SYS_ADMIN, &handler->conf->caps);
+
+       if (has_cgns && has_sys_admin)
                return true;
 
        tmpfspath = must_make_path(root, "/sys/fs/cgroup", NULL);
@@ -1633,6 +1669,19 @@ static bool cgfsng_mount(void *hdata, const char *root, int type)
                        free(controllerpath);
                        goto bad;
                }
+
+               if (has_cgns && !has_sys_admin) {
+                       /* If cgroup namespaces are supported but the container
+                        * will not have CAP_SYS_ADMIN after it has started we
+                        * need to mount the cgroups manually.
+                        */
+                       r = mount_cgroup_cgns_supported(h, controllerpath);
+                       free(controllerpath);
+                       if (r < 0)
+                               goto bad;
+                       continue;
+               }
+
                if (mount_cgroup_full(type, h, controllerpath, d->container_cgroup) < 0) {
                        free(controllerpath);
                        goto bad;
index 085953342c7507b3974d8ff13164fd66515e753a..780bc8bc936cdfec8364932ac6bd9cd73afd9dfe 100644 (file)
@@ -166,7 +166,7 @@ bool cgroup_chown(struct lxc_handler *handler)
 bool cgroup_mount(const char *root, struct lxc_handler *handler, int type)
 {
        if (ops)
-               return ops->mount_cgroup(handler->cgroup_data, root, type);
+               return ops->mount_cgroup(handler, root, type);
 
        return false;
 }
index 1d11c63b21ed7a20d306af7d007df3fb8321d78f..d55483df6e6228bdb6f6171bc1384d40b51ef0ec 100644 (file)
@@ -200,9 +200,6 @@ __thread struct lxc_conf *current_config;
 struct lxc_conf *current_config;
 #endif
 
-/* Declare this here, since we don't want to reshuffle the whole file. */
-static int in_caplist(int cap, struct lxc_list *caps);
-
 static struct mount_opt mount_opt[] = {
        { "async",         1, MS_SYNCHRONOUS },
        { "atime",         1, MS_NOATIME     },
index 17857ce891d34f4a698498274b143e211439531d..85538a2397e0e83114eb912fd4bbfcbd483f8778 100644 (file)
@@ -351,5 +351,6 @@ extern unsigned long add_required_remount_flags(const char *s, const char *d,
                                                unsigned long flags);
 extern int run_script(const char *name, const char *section, const char *script,
                      ...);
+extern int in_caplist(int cap, struct lxc_list *caps);
 
 #endif /* __LXC_CONF_H */