File 0001-core-introduce-new-Delegate-yes-no-property-controll.patch of Package systemd
Based on a931ad47a8623163a29d898224d8a8c1177ffdaf Mon Sep 17 00:00:00 2001
From: Lennart Poettering <lennart@poettering.net>
Date: Wed, 5 Nov 2014 17:57:23 +0100
Subject: [PATCH] core: introduce new Delegate=yes/no property controlling
creation of cgroup subhierarchies
For priviliged units this resource control property ensures that the
processes have all controllers systemd manages enabled.
For unpriviliged services (those with User= set) this ensures that
access rights to the service cgroup is granted to the user in question,
to create further subgroups. Note that this only applies to the
name=systemd hierarchy though, as access to other controllers is not
safe for unpriviliged processes.
Delegate=yes should be set for container scopes where a systemd instance
inside the container shall manage the hierarchies below its own cgroup
and have access to all controllers.
Delegate=yes should also be set for user@.service, so that systemd
--user can run, controlling its own cgroup tree.
This commit changes machined, systemd-nspawn@.service and user@.service
to set this boolean, in order to ensure that container management will
just work, and the user systemd instance can run fine.
---
man/systemd.resource-control.xml | 14 +++++++++++
src/core/cgroup.c | 22 +++++++++++++++--
src/core/cgroup.h | 2 +
src/core/dbus-cgroup.c | 42 ++++++++++++++++++++++++++++++++++
src/core/execute.c | 21 ++++++++++++++++-
src/core/execute.h | 2 +
src/core/load-fragment-gperf.gperf.m4 | 3 +-
src/core/mount.c | 1
src/core/service.c | 1
src/core/socket.c | 1
src/core/swap.c | 1
src/machine/machined-dbus.c | 4 +++
src/shared/cgroup-util.h | 3 +-
units/systemd-nspawn@.service.in | 1
units/user@.service.in | 1
15 files changed, 113 insertions(+), 6 deletions(-)
--- man/systemd.resource-control.xml
+++ man/systemd.resource-control.xml 2015-09-03 00:00:00.000000000 +0000
@@ -342,6 +342,20 @@ along with systemd; If not, see <http://
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>Delegate=</varname></term>
+
+ <listitem>
+ <para>Turns on delegation of further resource control
+ partitioning to processes of the unit. For unpriviliged
+ services (i.e. those using the <varname>User=</varname>
+ setting) this allows processes to create a subhierarchy
+ beneath its control group path. For priviliged services and
+ scopes this ensures the processes will have all control
+ group controllers enabled.</para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</refsect1>
--- src/core/cgroup.c
+++ src/core/cgroup.c 2015-09-03 00:00:00.000000000 +0000
@@ -94,14 +94,16 @@ void cgroup_context_dump(CGroupContext *
"%sCPUShares=%lu\n"
"%sBlockIOWeight=%lu\n"
"%sMemoryLimit=%" PRIu64 "\n"
- "%sDevicePolicy=%s\n",
+ "%sDevicePolicy=%s\n"
+ "%sDelegate=%s\n",
prefix, yes_no(c->cpu_accounting),
prefix, yes_no(c->blockio_accounting),
prefix, yes_no(c->memory_accounting),
prefix, c->cpu_shares,
prefix, c->blockio_weight,
prefix, c->memory_limit,
- prefix, cgroup_device_policy_to_string(c->device_policy));
+ prefix, cgroup_device_policy_to_string(c->device_policy),
+ prefix, yes_no(c->delegate));
LIST_FOREACH(device_allow, a, c->device_allow)
fprintf(f,
@@ -420,7 +422,8 @@ CGroupControllerMask cgroup_context_get_
c->memory_limit != (uint64_t) -1)
mask |= CGROUP_MEMORY;
- if (c->device_allow || c->device_policy != CGROUP_AUTO)
+ if (c->device_allow ||
+ c->device_policy != CGROUP_AUTO)
mask |= CGROUP_DEVICE;
return mask;
@@ -433,6 +436,19 @@ CGroupControllerMask unit_get_cgroup_mas
if (!c)
return 0;
+ /* If delegation is turned on, then turn on all cgroups,
+ * unless the process we fork into it is known to drop
+ * privileges anyway, and shouldn't get access to the
+ * controllers anyway. */
+
+ if (c->delegate) {
+ ExecContext *e;
+
+ e = unit_get_exec_context(u);
+ if (!e || exec_context_maintains_privileges(e))
+ return _CGROUP_CONTROLLER_MASK_ALL;
+ }
+
return cgroup_context_get_mask(c);
}
--- src/core/cgroup.h
+++ src/core/cgroup.h 2015-09-03 00:00:00.000000000 +0000
@@ -80,6 +80,8 @@ struct CGroupContext {
CGroupDevicePolicy device_policy;
LIST_HEAD(CGroupDeviceAllow, device_allow);
+
+ bool delegate;
};
#include "unit.h"
--- src/core/dbus-cgroup.c
+++ src/core/dbus-cgroup.c 2015-09-03 00:00:00.000000000 +0000
@@ -135,6 +135,7 @@ static int property_get_device_allow(
const sd_bus_vtable bus_cgroup_vtable[] = {
SD_BUS_VTABLE_START(0),
+ SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0),
SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0),
SD_BUS_PROPERTY("CPUShares", "t", bus_property_get_ulong, offsetof(CGroupContext, cpu_shares), 0),
SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0),
@@ -149,6 +150,39 @@ const sd_bus_vtable bus_cgroup_vtable[]
SD_BUS_VTABLE_END
};
+static int bus_cgroup_set_transient_property(
+ Unit *u,
+ CGroupContext *c,
+ const char *name,
+ sd_bus_message *message,
+ UnitSetPropertiesMode mode,
+ sd_bus_error *error) {
+
+ int r;
+
+ assert(u);
+ assert(c);
+ assert(name);
+ assert(message);
+
+ if (streq(name, "Delegate")) {
+ int b;
+
+ r = sd_bus_message_read(message, "b", &b);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ c->delegate = b;
+ unit_write_drop_in_private(u, mode, name, b ? "Delegate=yes" : "Delegate=no");
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
int bus_cgroup_set_property(
Unit *u,
CGroupContext *c,
@@ -524,6 +558,14 @@ int bus_cgroup_set_property(
}
return 1;
+
+ }
+
+ if (u->transient && u->load_state == UNIT_STUB) {
+ r = bus_cgroup_set_transient_property(u, c, name, message, mode, error);
+ if (r != 0)
+ return r;
+
}
return 0;
--- src/core/execute.c
+++ src/core/execute.c 2015-09-03 13:52:05.565519307 +0000
@@ -1167,6 +1167,7 @@ int exec_spawn(ExecCommand *command,
bool selinux_context_net,
CGroupControllerMask cgroup_supported,
const char *cgroup_path,
+ bool cgroup_delegate,
const char *unit_id,
usec_t watchdog_usec,
int idle_pipe[4],
@@ -1448,7 +1449,10 @@ int exec_spawn(ExecCommand *command,
}
#ifdef HAVE_PAM
- if (cgroup_path && context->user && context->pam_name) {
+ /* 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 (cgroup_path && context->user && cgroup_delegate) {
err = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER, cgroup_path, 0644, uid, gid);
if (err < 0) {
r = EXIT_CGROUP;
@@ -2273,6 +2277,21 @@ void exec_context_dump(ExecContext *c, F
prefix, c->apparmor_profile_ignore ? "-" : "", c->apparmor_profile);
}
+bool exec_context_maintains_privileges(ExecContext *c) {
+ assert(c);
+
+ /* Returns true if the process forked off would run run under
+ * an unchanged UID or as root. */
+
+ if (!c->user)
+ return true;
+
+ if (streq(c->user, "root") || streq(c->user, "0"))
+ return true;
+
+ return false;
+}
+
void exec_status_start(ExecStatus *s, pid_t pid) {
assert(s);
--- src/core/execute.h
+++ src/core/execute.h 2015-09-03 14:07:06.605520883 +0000
@@ -198,6 +198,7 @@ int exec_spawn(ExecCommand *command,
bool selinux_context_net,
CGroupControllerMask cgroup_mask,
const char *cgroup_path,
+ bool cgroup_delegate,
const char *unit_id,
usec_t watchdog_usec,
int pipe_fd[2],
@@ -224,6 +225,7 @@ void exec_context_dump(ExecContext *c, F
int exec_context_load_environment(const ExecContext *c, char ***l);
bool exec_context_may_touch_console(ExecContext *c);
+bool exec_context_maintains_privileges(ExecContext *c);
void exec_status_start(ExecStatus *s, pid_t pid);
void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, int status);
--- src/core/load-fragment-gperf.gperf.m4
+++ src/core/load-fragment-gperf.gperf.m4 2015-09-03 00:00:00.000000000 +0000
@@ -113,7 +113,8 @@ $1.BlockIOAccounting, config_
$1.BlockIOWeight, config_parse_blockio_weight, 0, offsetof($1, cgroup_context)
$1.BlockIODeviceWeight, config_parse_blockio_device_weight, 0, offsetof($1, cgroup_context)
$1.BlockIOReadBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)
-$1.BlockIOWriteBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)'
+$1.BlockIOWriteBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)
+$1.Delegate, config_parse_bool, 0, offsetof($1, cgroup_context.delegate)'
)m4_dnl
Unit.Description, config_parse_unit_string_printf, 0, offsetof(Unit, description)
Unit.Documentation, config_parse_documentation, 0, offsetof(Unit, documentation)
--- src/core/mount.c
+++ src/core/mount.c 2015-09-03 13:54:24.641520584 +0000
@@ -816,6 +816,7 @@ static int mount_spawn(Mount *m, ExecCom
false,
UNIT(m)->manager->cgroup_supported,
UNIT(m)->cgroup_path,
+ m->cgroup_context.delegate,
UNIT(m)->id,
0,
NULL,
--- src/core/service.c
+++ src/core/service.c 2015-09-03 13:59:14.850018797 +0000
@@ -1867,6 +1867,7 @@ static int service_spawn(
s->socket_fd_selinux_context_net,
UNIT(s)->manager->cgroup_supported,
path,
+ s->cgroup_context.delegate,
UNIT(s)->id,
s->watchdog_usec,
s->type == SERVICE_IDLE ? UNIT(s)->manager->idle_pipe : NULL,
--- src/core/socket.c
+++ src/core/socket.c 2015-09-03 13:59:07.806018550 +0000
@@ -1257,6 +1257,7 @@ static int socket_spawn(Socket *s, ExecC
s->selinux_context_from_net,
UNIT(s)->manager->cgroup_supported,
UNIT(s)->cgroup_path,
+ s->cgroup_context.delegate,
UNIT(s)->id,
0,
NULL,
--- src/core/swap.c
+++ src/core/swap.c 2015-09-03 13:59:02.081519346 +0000
@@ -648,6 +648,7 @@ static int swap_spawn(Swap *s, ExecComma
false,
UNIT(s)->manager->cgroup_supported,
UNIT(s)->cgroup_path,
+ s->cgroup_context.delegate,
UNIT(s)->id,
0,
NULL,
--- src/machine/machined-dbus.c
+++ src/machine/machined-dbus.c 2015-09-03 00:00:00.000000000 +0000
@@ -571,6 +571,10 @@ int manager_start_scope(
if (r < 0)
return r;
+ r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
+ if (r < 0)
+ return r;
+
if (more_properties) {
r = sd_bus_message_copy(m, more_properties, true);
if (r < 0)
--- src/shared/cgroup-util.h
+++ src/shared/cgroup-util.h 2015-09-03 00:00:00.000000000 +0000
@@ -34,7 +34,8 @@ typedef enum CGroupControllerMask {
CGROUP_CPUACCT = 2,
CGROUP_BLKIO = 4,
CGROUP_MEMORY = 8,
- CGROUP_DEVICE = 16
+ CGROUP_DEVICE = 16,
+ _CGROUP_CONTROLLER_MASK_ALL = 31
} CGroupControllerMask;
/*
--- units/systemd-nspawn@.service.in
+++ units/systemd-nspawn@.service.in 2015-09-03 14:00:02.818019437 +0000
@@ -13,6 +13,7 @@ Documentation=man:systemd-nspawn(1)
ExecStart=@bindir@/systemd-nspawn --quiet --keep-unit --boot --link-journal=guest --directory=/var/lib/container/%i
KillMode=mixed
Type=notify
+Delegate=yes
[Install]
WantedBy=multi-user.target
--- units/user@.service.in
+++ units/user@.service.in 2015-09-03 00:00:00.000000000 +0000
@@ -16,3 +16,4 @@ Type=notify
ExecStart=-@rootlibexecdir@/systemd --user
Slice=user-%i.slice
KillMode=mixed
+Delegate=yes