From aae1f3c47b09dfcecd17ec56a5fccfc60e52a220 Mon Sep 17 00:00:00 2001 From: Christian Seiler Date: Thu, 12 Sep 2013 01:44:43 +0200 Subject: [PATCH] cgroup: Add lxc_setup_mount_cgroup to setup /sys/fs/cgroup inside the container Add funbction to mount cgroup filesystem hierarchy into the container, allowing only access to the parts that the container should have access to, but none else. Signed-off-by: Christian Seiler Signed-off-by: Serge Hallyn --- src/lxc/cgroup.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++ src/lxc/cgroup.h | 2 + 2 files changed, 129 insertions(+) diff --git a/src/lxc/cgroup.c b/src/lxc/cgroup.c index ad95fc4681..876c60cbdb 100644 --- a/src/lxc/cgroup.c +++ b/src/lxc/cgroup.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -1200,6 +1201,132 @@ int lxc_setup_cgroup_devices(struct lxc_handler *h, struct lxc_list *cgroup_sett return do_setup_cgroup(h, cgroup_settings, true); } +int lxc_setup_mount_cgroup(const char *root, struct cgroup_process_info *base_info) +{ + size_t bufsz = strlen(root) + sizeof("/sys/fs/cgroup"); + char *path = NULL; + char **parts = NULL; + char *dirname = NULL; + char *abs_path = NULL; + char *abs_path2 = NULL; + struct cgroup_process_info *info; + int r, saved_errno = 0; + + path = calloc(1, bufsz); + if (!path) + return -1; + snprintf(path, bufsz, "%s/sys/fs/cgroup", root); + r = mount("cgroup_root", path, "tmpfs", MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_RELATIME, "size=10240k,mode=755"); + if (r < 0) { + SYSERROR("could not mount tmpfs to /sys/fs/cgroup in the container"); + return -1; + } + + /* now mount all the hierarchies we care about */ + for (info = base_info; info; info = info->next) { + size_t subsystem_count, i; + struct cgroup_mount_point *mp = info->designated_mount_point; + if (!mp) + mp = lxc_cgroup_find_mount_point(info->hierarchy, info->cgroup_path, true); + if (!mp) { + SYSERROR("could not find original mount point for cgroup hierarchy while trying to mount cgroup filesystem"); + goto out_error; + } + + subsystem_count = lxc_array_len((void **)info->hierarchy->subsystems); + parts = calloc(subsystem_count + 1, sizeof(char *)); + if (!parts) + goto out_error; + + for (i = 0; i < subsystem_count; i++) { + if (!strncmp(info->hierarchy->subsystems[i], "name=", 5)) + parts[i] = info->hierarchy->subsystems[i] + 5; + else + parts[i] = info->hierarchy->subsystems[i]; + } + dirname = lxc_string_join(",", (const char **)parts, false); + if (!dirname) + goto out_error; + + /* create subsystem directory */ + abs_path = lxc_append_paths(path, dirname); + if (!abs_path) + goto out_error; + r = mkdir_p(abs_path, 0755); + if (r < 0 && errno != EEXIST) { + SYSERROR("could not create cgroup subsystem directory /sys/fs/cgroup/%s", dirname); + goto out_error; + } + + /* create path for container's cgroup */ + abs_path2 = lxc_append_paths(abs_path, info->cgroup_path); + if (!abs_path2) + goto out_error; + r = mkdir_p(abs_path2, 0755); + if (r < 0 && errno != EEXIST) { + SYSERROR("could not create cgroup directory /sys/fs/cgroup/%s%s", dirname, info->cgroup_path); + goto out_error; + } + + free(abs_path); + abs_path = NULL; + + /* bind-mount container's cgroup to that directory */ + abs_path = cgroup_to_absolute_path(mp, info->cgroup_path, NULL); + if (!abs_path) + goto out_error; + r = mount(abs_path, abs_path2, "none", MS_BIND, 0); + if (r < 0) { + SYSERROR("error bind-mounting %s to %s", abs_path, abs_path2); + goto out_error; + } + + free(abs_path); + free(abs_path2); + abs_path = NULL; + abs_path2 = NULL; + + /* add symlinks for every single subsystem */ + if (subsystem_count > 1) { + for (i = 0; i < subsystem_count; i++) { + abs_path = lxc_append_paths(path, parts[i]); + if (!abs_path) + goto out_error; + r = symlink(dirname, abs_path); + if (r < 0) + WARN("could not create symlink %s -> %s in /sys/fs/cgroup of container", parts[i], dirname); + free(abs_path); + abs_path = NULL; + } + } + free(dirname); + free(parts); + dirname = NULL; + parts = NULL; + } + + /* try to remount the tmpfs readonly, since the container shouldn't + * change anything (this will also make sure that trying to create + * new cgroups outside the allowed area fails with an error instead + * of simply causing this to create directories in the tmpfs itself) + */ + mount(NULL, path, NULL, MS_REMOUNT|MS_RDONLY, NULL); + + free(path); + + return 0; + +out_error: + saved_errno = errno; + free(path); + free(dirname); + free(parts); + free(abs_path); + free(abs_path2); + errno = saved_errno; + return -1; +} + int lxc_cgroup_nrtasks_handler(struct lxc_handler *handler) { struct cgroup_process_info *info = handler->cgroup; diff --git a/src/lxc/cgroup.h b/src/lxc/cgroup.h index 25553901d9..ad9d596f01 100644 --- a/src/lxc/cgroup.h +++ b/src/lxc/cgroup.h @@ -160,6 +160,8 @@ struct lxc_list; extern int lxc_setup_cgroup_without_devices(struct lxc_handler *h, struct lxc_list *cgroup_settings); extern int lxc_setup_cgroup_devices(struct lxc_handler *h, struct lxc_list *cgroup_settings); +extern int lxc_setup_mount_cgroup(const char *root, struct cgroup_process_info *base_info); + extern int lxc_cgroup_nrtasks_handler(struct lxc_handler *handler); #endif