]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
core: change ownership of subcgroup we create recursively, it shall be owned by the...
authorLennart Poettering <lennart@poettering.net>
Mon, 24 Apr 2023 08:05:10 +0000 (10:05 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 27 Apr 2023 10:18:32 +0000 (12:18 +0200)
If we create a subcroup (regardless if the '.control' subgroup we
always created or one configured via DelegateSubgroup=) it's inside of
the delegated territory of the cgroup tree, hence it should be owned
fully by the unit's users. Hence do so.

src/core/execute.c
src/shared/cgroup-setup.c
src/shared/cgroup-setup.h

index a9e6f7bcae0e40ab1049ac716d3e36cf6ec4fc98..b32e341b61df0fc0ae5c18c8621a8c9c0fdd3dab 100644 (file)
@@ -4904,7 +4904,7 @@ static int exec_child(
                                 return log_unit_error_errno(unit, r, "Failed to acquire cgroup path: %m");
                         }
                         if (r > 0) {
-                                r = cg_set_access(SYSTEMD_CGROUP_CONTROLLER, p, uid, gid);
+                                r = cg_set_access_recursive(SYSTEMD_CGROUP_CONTROLLER, p, uid, gid);
                                 if (r < 0) {
                                         *exit_status = EXIT_CGROUP;
                                         return log_unit_error_errno(unit, r, "Failed to adjust control subgroup access: %m");
index 65be85101408bba80e2aecc0bc873cb817040b6d..6f3f9dd939ed10e122d994e7e0127fcf0a83f95c 100644 (file)
@@ -483,6 +483,82 @@ int cg_set_access(
         return 0;
 }
 
+struct access_callback_data {
+        uid_t uid;
+        gid_t gid;
+        int error;
+};
+
+static int access_callback(
+                RecurseDirEvent event,
+                const char *path,
+                int dir_fd,
+                int inode_fd,
+                const struct dirent *de,
+                const struct statx *sx,
+                void *userdata) {
+
+        struct access_callback_data *d = ASSERT_PTR(userdata);
+
+        if (!IN_SET(event, RECURSE_DIR_ENTER, RECURSE_DIR_ENTRY))
+                return RECURSE_DIR_CONTINUE;
+
+        assert(inode_fd >= 0);
+
+        /* fchown() doesn't support O_PATH fds, hence we use the /proc/self/fd/ trick */
+        if (chown(FORMAT_PROC_FD_PATH(inode_fd), d->uid, d->gid) < 0) {
+                log_debug_errno(errno, "Failed to change ownership of '%s', ignoring: %m", ASSERT_PTR(path));
+
+                if (d->error == 0) /* Return last error to caller */
+                        d->error = errno;
+        }
+
+        return RECURSE_DIR_CONTINUE;
+}
+
+int cg_set_access_recursive(
+                const char *controller,
+                const char *path,
+                uid_t uid,
+                gid_t gid) {
+
+        _cleanup_close_ int fd = -EBADF;
+        _cleanup_free_ char *fs = NULL;
+        int r;
+
+        /* A recursive version of cg_set_access(). But note that this one changes ownership of *all* files,
+         * not just the allowlist that cg_set_access() uses. Use cg_set_access() on the cgroup you want to
+         * delegate, and cg_set_access_recursive() for any subcrgoups you might want to create below it. */
+
+        if (!uid_is_valid(uid) && !gid_is_valid(gid))
+                return 0;
+
+        r = cg_get_path(controller, path, NULL, &fs);
+        if (r < 0)
+                return r;
+
+        fd = open(fs, O_DIRECTORY|O_CLOEXEC|O_RDONLY);
+        if (fd < 0)
+                return -errno;
+
+        struct access_callback_data d = {
+                .uid = uid,
+                .gid = gid,
+        };
+
+        r = recurse_dir(fd,
+                        fs,
+                        /* statx_mask= */ 0,
+                        /* n_depth_max= */ UINT_MAX,
+                        RECURSE_DIR_SAME_MOUNT|RECURSE_DIR_INODE_FD|RECURSE_DIR_TOPLEVEL,
+                        access_callback,
+                        &d);
+        if (r < 0)
+                return r;
+
+        return -d.error;
+}
+
 int cg_migrate(
                 const char *cfrom,
                 const char *pfrom,
index 13f836bd90a218102b46378643bbb704648100af..1b6f0716c634232110f7b4f3670ccc88bbf62ef2 100644 (file)
@@ -24,6 +24,7 @@ int cg_attach_fallback(const char *controller, const char *path, pid_t pid);
 int cg_create_and_attach(const char *controller, const char *path, pid_t pid);
 
 int cg_set_access(const char *controller, const char *path, uid_t uid, gid_t gid);
+int cg_set_access_recursive(const char *controller, const char *path, uid_t uid, gid_t gid);
 
 int cg_migrate(const char *cfrom, const char *pfrom, const char *cto, const char *pto, CGroupFlags flags);
 int cg_migrate_recursive(const char *cfrom, const char *pfrom, const char *cto, const char *pto, CGroupFlags flags);