summaryrefslogtreecommitdiff
path: root/src/shared/cgroup-setup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/cgroup-setup.c')
-rw-r--r--src/shared/cgroup-setup.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/src/shared/cgroup-setup.c b/src/shared/cgroup-setup.c
index 65be851014..6f3f9dd939 100644
--- a/src/shared/cgroup-setup.c
+++ b/src/shared/cgroup-setup.c
@@ -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,