cgroup-util: merge cg_set_tasks_access() and cg-set_group_access() into one
We never use these functions seperately, hence don't bother splitting them into to. Also, simplify things a bit, and maintain tables for the attribute files to chown. Let's also update those tables a bit, and include thenew "cgroup.threads" file in it, that needs to be delegated too, according to the documentation.
This commit is contained in:
parent
deb3b156ac
commit
62b9bb2661
|
@ -876,115 +876,87 @@ int cg_attach_fallback(const char *controller, const char *path, pid_t pid) {
|
|||
return r;
|
||||
}
|
||||
|
||||
int cg_set_group_access(
|
||||
int cg_set_access(
|
||||
const char *controller,
|
||||
const char *path,
|
||||
mode_t mode,
|
||||
uid_t uid,
|
||||
gid_t gid) {
|
||||
|
||||
_cleanup_free_ char *fs = NULL;
|
||||
int r;
|
||||
struct Attribute {
|
||||
const char *name;
|
||||
bool fatal;
|
||||
};
|
||||
|
||||
if (mode == MODE_INVALID && uid == UID_INVALID && gid == GID_INVALID)
|
||||
/* cgroupsv1, aka legacy/non-unified */
|
||||
static const struct Attribute legacy_attributes[] = {
|
||||
{ "cgroup.procs", true },
|
||||
{ "tasks", false },
|
||||
{ "cgroup.clone_children", false },
|
||||
{},
|
||||
};
|
||||
|
||||
/* cgroupsv2, aka unified */
|
||||
static const struct Attribute unified_attributes[] = {
|
||||
{ "cgroup.procs", true },
|
||||
{ "cgroup.subtree_control", true },
|
||||
{ "cgroup.threads", false },
|
||||
{},
|
||||
};
|
||||
|
||||
static const struct Attribute* const attributes[] = {
|
||||
[false] = legacy_attributes,
|
||||
[true] = unified_attributes,
|
||||
};
|
||||
|
||||
_cleanup_free_ char *fs = NULL;
|
||||
const struct Attribute *i;
|
||||
int r, unified;
|
||||
|
||||
assert(path);
|
||||
|
||||
if (uid == UID_INVALID && gid == GID_INVALID)
|
||||
return 0;
|
||||
|
||||
if (mode != MODE_INVALID)
|
||||
mode &= 0777;
|
||||
unified = cg_unified_controller(controller);
|
||||
if (unified < 0)
|
||||
return unified;
|
||||
|
||||
/* Configure access to the cgroup itself */
|
||||
r = cg_get_path(controller, path, NULL, &fs);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = chmod_and_chown(fs, mode, uid, gid);
|
||||
r = chmod_and_chown(fs, 0755, uid, gid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = cg_hybrid_unified();
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0 && streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
|
||||
r = cg_set_group_access(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, mode, uid, gid);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to set group access on compatibility systemd cgroup %s, ignoring: %m", path);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cg_set_task_access(
|
||||
const char *controller,
|
||||
const char *path,
|
||||
mode_t mode,
|
||||
uid_t uid,
|
||||
gid_t gid) {
|
||||
|
||||
_cleanup_free_ char *fs = NULL;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
|
||||
if (mode == MODE_INVALID && uid == UID_INVALID && gid == GID_INVALID)
|
||||
return 0;
|
||||
|
||||
if (mode != MODE_INVALID)
|
||||
mode &= 0666;
|
||||
|
||||
/* For both the legacy and unified hierarchies, "cgroup.procs" is the main entry point for PIDs */
|
||||
r = cg_get_path(controller, path, "cgroup.procs", &fs);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = chmod_and_chown(fs, mode, uid, gid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = cg_unified_controller(controller);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
const char *fn;
|
||||
|
||||
/* Compatibility: on cgroupsv1 always keep values for the legacy files "tasks" and
|
||||
* "cgroup.clone_children" in sync with "cgroup.procs". Since this is legacy stuff, we don't care if
|
||||
* this fails. */
|
||||
|
||||
FOREACH_STRING(fn,
|
||||
"tasks",
|
||||
"cgroup.clone_children") {
|
||||
|
||||
fs = mfree(fs);
|
||||
|
||||
r = cg_get_path(controller, path, fn, &fs);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to get path for %s of %s, ignoring: %m", fn, path);
|
||||
|
||||
r = chmod_and_chown(fs, mode, uid, gid);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to to change ownership/access mode for %s of %s, ignoring: %m", fn, path);
|
||||
}
|
||||
} else {
|
||||
/* On the unified controller, we want to permit subtree controllers too. */
|
||||
|
||||
/* Configure access to the cgroup's attributes */
|
||||
for (i = attributes[unified]; i->name; i++) {
|
||||
fs = mfree(fs);
|
||||
r = cg_get_path(controller, path, "cgroup.subtree_control", &fs);
|
||||
|
||||
r = cg_get_path(controller, path, i->name, &fs);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = chmod_and_chown(fs, mode, uid, gid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = chmod_and_chown(fs, 0644, uid, gid);
|
||||
if (r < 0) {
|
||||
if (i->fatal)
|
||||
return r;
|
||||
|
||||
log_debug_errno(r, "Failed to set access on cgroup %s, ignoring: %m", fs);
|
||||
}
|
||||
}
|
||||
|
||||
r = cg_hybrid_unified();
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0 && streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
|
||||
/* Always propagate access mode from unified to legacy controller */
|
||||
|
||||
r = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, mode, uid, gid);
|
||||
if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
|
||||
r = cg_hybrid_unified();
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to set task access on compatibility systemd cgroup %s, ignoring: %m", path);
|
||||
return r;
|
||||
if (r > 0) {
|
||||
/* Always propagate access mode from unified to legacy controller */
|
||||
r = cg_set_access(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, uid, gid);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to set access on compatibility systemd cgroup %s, ignoring: %m", path);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -188,8 +188,7 @@ int cg_set_attribute(const char *controller, const char *path, const char *attri
|
|||
int cg_get_attribute(const char *controller, const char *path, const char *attribute, char **ret);
|
||||
int cg_get_keyed_attribute(const char *controller, const char *path, const char *attribute, const char **keys, char **values);
|
||||
|
||||
int cg_set_group_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid);
|
||||
int cg_set_task_access(const char *controller, const char *path, mode_t mode, uid_t uid, gid_t gid);
|
||||
int cg_set_access(const char *controller, const char *path, uid_t uid, gid_t gid);
|
||||
|
||||
int cg_set_xattr(const char *controller, const char *path, const char *name, const void *value, size_t size, int flags);
|
||||
int cg_get_xattr(const char *controller, const char *path, const char *name, void *value, size_t size);
|
||||
|
|
|
@ -3009,17 +3009,12 @@ static int exec_child(
|
|||
}
|
||||
}
|
||||
|
||||
/* If delegation is enabled we'll pass ownership of the cgroup
|
||||
* (but only in systemd's own controller hierarchy!) to the
|
||||
* user of the new process. */
|
||||
/* If delegation is enabled we'll pass ownership of the cgroup to the user of the new process. On cgroupsv1
|
||||
* this is only about systemd's own hierarchy, i.e. not the controller hierarchies, simply because that's not
|
||||
* safe. On cgroupsv2 there's only one hierarchy anyway, and delegation is safe there, hence in that case only
|
||||
* touch a single hierarchy too. */
|
||||
if (params->cgroup_path && context->user && (params->flags & EXEC_CGROUP_DELEGATE)) {
|
||||
r = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, 0644, uid, gid);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_CGROUP;
|
||||
return log_unit_error_errno(unit, r, "Failed to adjust control group access: %m");
|
||||
}
|
||||
|
||||
r = cg_set_group_access(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, 0755, uid, gid);
|
||||
r = cg_set_access(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, uid, gid);
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_CGROUP;
|
||||
return log_unit_error_errno(unit, r, "Failed to adjust control group access: %m");
|
||||
|
|
Loading…
Reference in New Issue