From af869b9c37f11efe078fca67734d93d84cb43e11 Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Tue, 10 Nov 2015 19:38:40 -0600 Subject: [PATCH] chown cgroup files after chowning dirs cgmanager used to do this for us. Signed-off-by: Serge Hallyn --- cgfs.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- cgfs.h | 2 +- lxcfs.c | 7 +----- 3 files changed, 79 insertions(+), 8 deletions(-) diff --git a/cgfs.c b/cgfs.c index bf4322b7..672cc9b6 100644 --- a/cgfs.c +++ b/cgfs.c @@ -42,6 +42,15 @@ char *basedir; #define basedir RUNTIME_PATH "/lxcfs/controllers" +int is_dir(const char *path) +{ + struct stat statbuf; + int ret = stat(path, &statbuf); + if (ret == 0 && S_ISDIR(statbuf.st_mode)) + return 1; + return 0; +} + char *must_copy_string(const char *str) { char *dup = NULL; @@ -351,7 +360,43 @@ bool cgfs_set_value(const char *controller, const char *cgroup, const char *file return write_string(fnam, value); } -int cgfs_create(const char *controller, const char *cg) +// Chown all the files in the cgroup directory. We do this when we create +// a cgroup on behalf of a user. +static void chown_all_cgroup_files(const char *dirname, uid_t uid, gid_t gid) +{ + struct dirent dirent, *direntp; + char path[MAXPATHLEN]; + size_t len; + DIR *d; + int ret; + + len = strlen(dirname); + if (len >= MAXPATHLEN) { + fprintf(stderr, "chown_all_cgroup_files: pathname too long: %s\n", dirname); + return; + } + + d = opendir(dirname); + if (!d) { + fprintf(stderr, "chown_all_cgroup_files: failed to open %s\n", dirname); + return; + } + + while (readdir_r(d, &dirent, &direntp) == 0 && direntp) { + if (!strcmp(direntp->d_name, ".") || !strcmp(direntp->d_name, "..")) + continue; + ret = snprintf(path, MAXPATHLEN, "%s/%s", dirname, direntp->d_name); + if (ret < 0 || ret >= MAXPATHLEN) { + fprintf(stderr, "chown_all_cgroup_files: pathname too long under %s\n", dirname); + continue; + } + if (chown(path, uid, gid) < 0) + fprintf(stderr, "Failed to chown file %s to %u:%u", path, uid, gid); + } + closedir(d); +} + +int cgfs_create(const char *controller, const char *cg, uid_t uid, gid_t gid) { size_t len; char *dirnam, *tmpc = find_mounted_controller(controller); @@ -362,8 +407,18 @@ int cgfs_create(const char *controller, const char *cg) len = strlen(basedir) + strlen(tmpc) + strlen(cg) + 3; dirnam = alloca(len); snprintf(dirnam, len, "%s/%s/%s", basedir,tmpc, cg); + if (mkdir(dirnam, 0755) < 0) return -errno; + + if (uid == 0 && gid == 0) + return 0; + + if (chown(dirnam, uid, gid) < 0) + return -errno; + + chown_all_cgroup_files(dirnam, uid, gid); + return 0; } @@ -452,6 +507,22 @@ bool cgfs_chmod_file(const char *controller, const char *file, mode_t mode) return true; } +static int chown_tasks_files(const char *dirname, uid_t uid, gid_t gid) +{ + size_t len; + char *fname; + + len = strlen(dirname) + strlen("/cgroup.procs") + 1; + fname = alloca(len); + snprintf(fname, len, "%s/tasks", dirname); + if (chown(fname, uid, gid) != 0) + return -errno; + snprintf(fname, len, "%s/cgroup.procs", dirname); + if (chown(fname, uid, gid) != 0) + return -errno; + return 0; +} + int cgfs_chown_file(const char *controller, const char *file, uid_t uid, gid_t gid) { size_t len; @@ -465,6 +536,11 @@ int cgfs_chown_file(const char *controller, const char *file, uid_t uid, gid_t g snprintf(pathname, len, "%s/%s/%s", basedir, tmpc, file); if (chown(pathname, uid, gid) < 0) return -errno; + + if (is_dir(pathname)) + // like cgmanager did, we want to chown the tasks file as well + return chown_tasks_files(pathname, uid, gid); + return 0; } diff --git a/cgfs.h b/cgfs.h index 84f1a29c..5ef60fb6 100644 --- a/cgfs.h +++ b/cgfs.h @@ -6,7 +6,7 @@ char *must_copy_string(const char *str); bool cgfs_set_value(const char *controller, const char *cgroup, const char *file, const char *value); -int cgfs_create(const char *controller, const char *cg); +int cgfs_create(const char *controller, const char *cg, uid_t uid, gid_t gid); bool cgfs_remove(const char *controller, const char *cg); bool cgfs_chmod_file(const char *controller, const char *file, mode_t mode); int cgfs_chown_file(const char *controller, const char *cg, uid_t uid, gid_t gid); diff --git a/lxcfs.c b/lxcfs.c index 19c781df..af734d5f 100644 --- a/lxcfs.c +++ b/lxcfs.c @@ -1594,12 +1594,7 @@ int cg_mkdir(const char *path, mode_t mode) goto out; } - ret = cgfs_create(controller, cgroup); - if (ret) - goto out; - - if (fc->uid != 0 || fc->gid != 0) - ret = cgfs_chown_file(controller, cgroup, fc->uid, fc->gid); + ret = cgfs_create(controller, cgroup, fc->uid, fc->gid); out: free(cgdir);