pid1: add D-Bus API for removing delegated subcgroups
When running unprivileged containers, we run into a scenario where an unpriv owned cgroup has a subcgroup delegated to another user (i.e. the container's own UIDs). When the owner of that cgroup dies without cleaning it up then the unpriv service manager might encounter a cgroup it cannot delete anymore. Let's address that: let's expose a method call on the service manager (primarly in PID1) that can be used to delete a subcgroup of a unit one owns. This would then allow the unpriv service manager to ask the priv service manager to get rid of such a cgroup. This commit only adds the method call, the next commit then adds the code that makes use of this.
This commit is contained in:
@@ -1594,6 +1594,59 @@ int bus_unit_method_attach_processes(sd_bus_message *message, void *userdata, sd
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
int bus_unit_method_remove_subgroup(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
Unit *u = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
assert(message);
|
||||
|
||||
/* This removes a subcgroup of the unit, regardless which user owns the subcgroup. This is useful
|
||||
* when cgroup delegation is enabled for a unit, and the unit subdelegates the cgroup further */
|
||||
|
||||
r = mac_selinux_unit_access_check(u, message, "stop", error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
const char *path;
|
||||
uint64_t flags;
|
||||
r = sd_bus_message_read(message, "st", &path, &flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* No flags defined for now. */
|
||||
if (flags != 0)
|
||||
return sd_bus_reply_method_errorf(message, SD_BUS_ERROR_INVALID_ARGS, "Invalid 'flags' parameter '%" PRIu64 "'", flags);
|
||||
|
||||
if (!unit_cgroup_delegate(u))
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Subcgroup removal not available on non-delegated units.");
|
||||
|
||||
if (!path_is_absolute(path))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Control group path is not absolute: %s", path);
|
||||
|
||||
if (!path_is_normalized(path))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Control group path is not normalized: %s", path);
|
||||
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
uid_t sender_uid;
|
||||
r = sd_bus_creds_get_euid(creds, &sender_uid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Allow this only if the client is privileged, is us, or is the user of the unit itself. */
|
||||
if (sender_uid != 0 && sender_uid != getuid() && sender_uid != u->ref_uid)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Client is not permitted to alter cgroup.");
|
||||
|
||||
r = unit_remove_subcgroup(u, path);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to remove subgroup %s: %m", path);
|
||||
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
const sd_bus_vtable bus_unit_cgroup_vtable[] = {
|
||||
SD_BUS_VTABLE_START(0),
|
||||
SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
|
||||
@@ -1633,6 +1686,12 @@ const sd_bus_vtable bus_unit_cgroup_vtable[] = {
|
||||
bus_unit_method_attach_processes,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
||||
SD_BUS_METHOD_WITH_ARGS("RemoveSubgroup",
|
||||
SD_BUS_ARGS("s", subcgroup, "t", flags),
|
||||
SD_BUS_NO_RESULT,
|
||||
bus_unit_method_remove_subgroup,
|
||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
||||
SD_BUS_VTABLE_END
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user