systemd-250-11

Resolves: #2120604,#2121144
This commit is contained in:
Jan Macku 2022-08-25 10:24:32 +02:00
parent 2891ff393e
commit 56f1ee916b
3 changed files with 405 additions and 1 deletions

View File

@ -0,0 +1,343 @@
From f23d0328e563fa5534377297153daa098664147f Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Wed, 1 Jun 2022 10:15:06 +0200
Subject: [PATCH] scope: allow unprivileged delegation on scopes
Previously it was possible to set delegate property for scope, but you
were not able to allow unprivileged process to manage the scope's cgroup
hierarchy. This is useful when launching manager process that will run
unprivileged but is supposed to manage its own (scope) sub-hierarchy.
Fixes #21683
(cherry picked from commit 03860190fefce8bbea3a6f0e77919b882ade517c)
Resolves: #2120604
---
src/basic/unit-def.c | 1 +
src/basic/unit-def.h | 1 +
src/core/dbus-scope.c | 6 ++
src/core/scope.c | 130 ++++++++++++++++++++++++++++++++-----
src/core/scope.h | 3 +
src/shared/bus-unit-util.c | 5 ++
test/units/testsuite-19.sh | 14 ++++
7 files changed, 143 insertions(+), 17 deletions(-)
diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c
index 2667e61dc4..9408141842 100644
--- a/src/basic/unit-def.c
+++ b/src/basic/unit-def.c
@@ -170,6 +170,7 @@ DEFINE_STRING_TABLE_LOOKUP(path_state, PathState);
static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
[SCOPE_DEAD] = "dead",
[SCOPE_RUNNING] = "running",
+ [SCOPE_START_CHOWN] = "start-chown",
[SCOPE_ABANDONED] = "abandoned",
[SCOPE_STOP_SIGTERM] = "stop-sigterm",
[SCOPE_STOP_SIGKILL] = "stop-sigkill",
diff --git a/src/basic/unit-def.h b/src/basic/unit-def.h
index f80e554d2b..5fcd51c095 100644
--- a/src/basic/unit-def.h
+++ b/src/basic/unit-def.h
@@ -114,6 +114,7 @@ typedef enum PathState {
typedef enum ScopeState {
SCOPE_DEAD,
+ SCOPE_START_CHOWN,
SCOPE_RUNNING,
SCOPE_ABANDONED,
SCOPE_STOP_SIGTERM,
diff --git a/src/core/dbus-scope.c b/src/core/dbus-scope.c
index 109ad6f2ef..0f59622166 100644
--- a/src/core/dbus-scope.c
+++ b/src/core/dbus-scope.c
@@ -186,6 +186,12 @@ int bus_scope_set_property(
r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, flags, error);
if (r != 0)
return r;
+
+ if (streq(name, "User"))
+ return bus_set_transient_user_relaxed(u, name, &s->user, message, flags, error);
+
+ if (streq(name, "Group"))
+ return bus_set_transient_user_relaxed(u, name, &s->group, message, flags, error);
}
return 0;
diff --git a/src/core/scope.c b/src/core/scope.c
index 63d3288caf..a4da45ac43 100644
--- a/src/core/scope.c
+++ b/src/core/scope.c
@@ -6,6 +6,7 @@
#include "alloc-util.h"
#include "dbus-scope.h"
#include "dbus-unit.h"
+#include "exit-status.h"
#include "load-dropin.h"
#include "log.h"
#include "process-util.h"
@@ -18,9 +19,11 @@
#include "strv.h"
#include "unit-name.h"
#include "unit.h"
+#include "user-util.h"
static const UnitActiveState state_translation_table[_SCOPE_STATE_MAX] = {
[SCOPE_DEAD] = UNIT_INACTIVE,
+ [SCOPE_START_CHOWN] = UNIT_ACTIVATING,
[SCOPE_RUNNING] = UNIT_ACTIVE,
[SCOPE_ABANDONED] = UNIT_ACTIVE,
[SCOPE_STOP_SIGTERM] = UNIT_DEACTIVATING,
@@ -39,6 +42,7 @@ static void scope_init(Unit *u) {
s->runtime_max_usec = USEC_INFINITY;
s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
u->ignore_on_isolate = true;
+ s->user = s->group = NULL;
}
static void scope_done(Unit *u) {
@@ -50,6 +54,9 @@ static void scope_done(Unit *u) {
s->controller_track = sd_bus_track_unref(s->controller_track);
s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source);
+
+ s->user = mfree(s->user);
+ s->group = mfree(s->group);
}
static usec_t scope_running_timeout(Scope *s) {
@@ -107,7 +114,7 @@ static void scope_set_state(Scope *s, ScopeState state) {
old_state = s->state;
s->state = state;
- if (!IN_SET(state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
+ if (!IN_SET(state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL, SCOPE_START_CHOWN))
s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source);
if (IN_SET(state, SCOPE_DEAD, SCOPE_FAILED)) {
@@ -353,26 +360,72 @@ fail:
scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
}
-static int scope_start(Unit *u) {
- Scope *s = SCOPE(u);
+static int scope_enter_start_chown(Scope *s) {
+ Unit *u = UNIT(s);
+ pid_t pid;
int r;
assert(s);
+ assert(s->user);
- if (unit_has_name(u, SPECIAL_INIT_SCOPE))
- return -EPERM;
+ r = scope_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), u->manager->default_timeout_start_usec));
+ if (r < 0)
+ return r;
- if (s->state == SCOPE_FAILED)
- return -EPERM;
+ r = unit_fork_helper_process(u, "(sd-chown-cgroup)", &pid);
+ if (r < 0)
+ goto fail;
- /* We can't fulfill this right now, please try again later */
- if (IN_SET(s->state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
- return -EAGAIN;
+ if (r == 0) {
+ uid_t uid = UID_INVALID;
+ gid_t gid = GID_INVALID;
- assert(s->state == SCOPE_DEAD);
+ if (!isempty(s->user)) {
+ const char *user = s->user;
- if (!u->transient && !MANAGER_IS_RELOADING(u->manager))
- return -ENOENT;
+ r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0);
+ if (r < 0) {
+ log_unit_error_errno(UNIT(s), r, "Failed to resolve user \"%s\": %m", user);
+ _exit(EXIT_USER);
+ }
+ }
+
+ if (!isempty(s->group)) {
+ const char *group = s->group;
+
+ r = get_group_creds(&group, &gid, 0);
+ if (r < 0) {
+ log_unit_error_errno(UNIT(s), r, "Failed to resolve group \"%s\": %m", group);
+ _exit(EXIT_GROUP);
+ }
+ }
+
+ r = cg_set_access(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, uid, gid);
+ if (r < 0) {
+ log_unit_error_errno(UNIT(s), r, "Failed to adjust control group access: %m");
+ _exit(EXIT_CGROUP);
+ }
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ r = unit_watch_pid(UNIT(s), pid, true);
+ if (r < 0)
+ goto fail;
+
+ scope_set_state(s, SCOPE_START_CHOWN);
+
+ return 1;
+fail:
+ s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source);
+ return r;
+}
+
+static int scope_enter_running(Scope *s) {
+ Unit *u = UNIT(s);
+ int r;
+
+ assert(s);
(void) bus_scope_track_controller(s);
@@ -380,9 +433,6 @@ static int scope_start(Unit *u) {
if (r < 0)
return r;
- (void) unit_realize_cgroup(u);
- (void) unit_reset_accounting(u);
-
unit_export_state_files(u);
r = unit_attach_pids_to_cgroup(u, u->pids, NULL);
@@ -416,6 +466,37 @@ static int scope_start(Unit *u) {
return 1;
}
+static int scope_start(Unit *u) {
+ Scope *s = SCOPE(u);
+
+ assert(s);
+
+ if (unit_has_name(u, SPECIAL_INIT_SCOPE))
+ return -EPERM;
+
+ if (s->state == SCOPE_FAILED)
+ return -EPERM;
+
+ /* We can't fulfill this right now, please try again later */
+ if (IN_SET(s->state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
+ return -EAGAIN;
+
+ assert(s->state == SCOPE_DEAD);
+
+ if (!u->transient && !MANAGER_IS_RELOADING(u->manager))
+ return -ENOENT;
+
+ (void) unit_realize_cgroup(u);
+ (void) unit_reset_accounting(u);
+
+ /* We check only for User= option to keep behavior consistent with logic for service units,
+ * i.e. having 'Delegate=true Group=foo' w/o specifing User= has no effect. */
+ if (s->user && unit_cgroup_delegate(u))
+ return scope_enter_start_chown(s);
+
+ return scope_enter_running(s);
+}
+
static int scope_stop(Unit *u) {
Scope *s = SCOPE(u);
@@ -547,7 +628,17 @@ static void scope_notify_cgroup_empty_event(Unit *u) {
}
static void scope_sigchld_event(Unit *u, pid_t pid, int code, int status) {
- assert(u);
+ Scope *s = SCOPE(u);
+
+ assert(s);
+
+ if (s->state == SCOPE_START_CHOWN) {
+ if (!is_clean_exit(code, status, EXIT_CLEAN_COMMAND, NULL))
+ scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
+ else
+ scope_enter_running(s);
+ return;
+ }
/* If we get a SIGCHLD event for one of the processes we were interested in, then we look for others to
* watch, under the assumption that we'll sooner or later get a SIGCHLD for them, as the original
@@ -585,6 +676,11 @@ static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *user
scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
break;
+ case SCOPE_START_CHOWN:
+ log_unit_warning(UNIT(s), "User lookup timed out. Entering failed state.");
+ scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
+ break;
+
default:
assert_not_reached();
}
diff --git a/src/core/scope.h b/src/core/scope.h
index 03a9ba4324..def1541652 100644
--- a/src/core/scope.h
+++ b/src/core/scope.h
@@ -34,6 +34,9 @@ struct Scope {
bool was_abandoned;
sd_event_source *timer_event_source;
+
+ char *user;
+ char *group;
};
extern const UnitVTable scope_vtable;
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index c211fe34d5..33b0b947b7 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -2130,6 +2130,11 @@ static int bus_append_scope_property(sd_bus_message *m, const char *field, const
if (streq(field, "TimeoutStopSec"))
return bus_append_parse_sec_rename(m, field, eq);
+ /* Scope units don't have execution context but we still want to allow setting these two,
+ * so let's handle them separately. */
+ if (STR_IN_SET(field, "User", "Group"))
+ return bus_append_string(m, field, eq);
+
return 0;
}
diff --git a/test/units/testsuite-19.sh b/test/units/testsuite-19.sh
index ee4eb8431e..6ce6d3d429 100755
--- a/test/units/testsuite-19.sh
+++ b/test/units/testsuite-19.sh
@@ -3,6 +3,16 @@
set -eux
set -o pipefail
+test_scope_unpriv_delegation() {
+ useradd test ||:
+ trap "userdel -r test" RETURN
+
+ systemd-run --uid=test -p User=test -p Delegate=yes --slice workload.slice --unit workload0.scope --scope \
+ test -w /sys/fs/cgroup/workload.slice/workload0.scope -a \
+ -w /sys/fs/cgroup/workload.slice/workload0.scope/cgroup.procs -a \
+ -w /sys/fs/cgroup/workload.slice/workload0.scope/cgroup.subtree_control
+}
+
if grep -q cgroup2 /proc/filesystems ; then
systemd-run --wait --unit=test0.service -p "DynamicUser=1" -p "Delegate=" \
test -w /sys/fs/cgroup/system.slice/test0.service/ -a \
@@ -31,6 +41,10 @@ if grep -q cgroup2 /proc/filesystems ; then
# And now check again, "io" should have vanished
grep -qv io /sys/fs/cgroup/system.slice/cgroup.controllers
+
+ # Check that unprivileged delegation works for scopes
+ test_scope_unpriv_delegation
+
else
echo "Skipping TEST-19-DELEGATE, as the kernel doesn't actually support cgroup v2" >&2
fi

View File

@ -0,0 +1,55 @@
From ef6d76202a28d374a96c4dff1e40c7bd4551de0c Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Wed, 24 Aug 2022 17:18:47 +0200
Subject: [PATCH] udev/net_id: add "rhel-9.1" naming scheme
RHEL-only
Resolves: #2121144
---
man/systemd.net-naming-scheme.xml | 6 ++++++
src/shared/netif-naming-scheme.c | 1 +
src/shared/netif-naming-scheme.h | 1 +
3 files changed, 8 insertions(+)
diff --git a/man/systemd.net-naming-scheme.xml b/man/systemd.net-naming-scheme.xml
index 73d08b681d..23bfcead1f 100644
--- a/man/systemd.net-naming-scheme.xml
+++ b/man/systemd.net-naming-scheme.xml
@@ -415,6 +415,12 @@
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><constant>rhel-9.1</constant></term>
+
+ <listitem><para>Same as naming scheme <constant>rhel-9.0</constant>.</para></listitem>
+ </varlistentry>
+
</variablelist>
<para>Note that <constant>latest</constant> may be used to denote the latest scheme known (to this
diff --git a/src/shared/netif-naming-scheme.c b/src/shared/netif-naming-scheme.c
index 44d011a9b7..adda731f63 100644
--- a/src/shared/netif-naming-scheme.c
+++ b/src/shared/netif-naming-scheme.c
@@ -24,6 +24,7 @@ static const NamingScheme naming_schemes[] = {
{ "v249", NAMING_V249 },
{ "v250", NAMING_V250 },
{ "rhel-9.0", NAMING_RHEL_9_0 },
+ { "rhel-9.1", NAMING_RHEL_9_1 },
/* … add more schemes here, as the logic to name devices is updated … */
EXTRA_NET_NAMING_MAP
diff --git a/src/shared/netif-naming-scheme.h b/src/shared/netif-naming-scheme.h
index 5c86cb4545..f27c0593c3 100644
--- a/src/shared/netif-naming-scheme.h
+++ b/src/shared/netif-naming-scheme.h
@@ -49,6 +49,7 @@ typedef enum NamingSchemeFlags {
NAMING_V249 = NAMING_V247 | NAMING_SLOT_FUNCTION_ID | NAMING_16BIT_INDEX | NAMING_REPLACE_STRICTLY,
NAMING_V250 = NAMING_V249 | NAMING_XEN_VIF,
NAMING_RHEL_9_0 = NAMING_V250 | NAMING_BRIDGE_MULTIFUNCTION_SLOT,
+ NAMING_RHEL_9_1 = NAMING_RHEL_9_0,
EXTRA_NET_NAMING_SCHEMES

View File

@ -21,7 +21,7 @@
Name: systemd
Url: https://www.freedesktop.org/wiki/Software/systemd
Version: 250
Release: 10%{?dist}
Release: 11%{?dist}
# For a breakdown of the licensing, see README
License: LGPLv2+ and MIT and GPLv2+
Summary: System and Service Manager
@ -413,6 +413,8 @@ Patch0332: 0332-hwdb-analyzers-Clarify-the-type-of-devices-we-want-l.patch
Patch0333: 0333-hwdb-Add-Greaseweazle-drives-to-the-list-of-analyzer.patch
Patch0334: 0334-hwdb-Apply-existing-accel-orientation-quirk-to-all-C.patch
Patch0335: 0335-shared-install-fix-crash-when-reenable-is-called-wit.patch
Patch0336: 0336-scope-allow-unprivileged-delegation-on-scopes.patch
Patch0337: 0337-udev-net_id-add-rhel-9.1-naming-scheme.patch
# Downstream-only patches (90009999)
@ -1194,6 +1196,10 @@ getent passwd systemd-oom &>/dev/null || useradd -r -l -g systemd-oom -d / -s /s
%files standalone-sysusers -f .file-list-standalone-sysusers
%changelog
* Thu Aug 25 2022 systemd maintenance team <systemd-maint@redhat.com> - 250-11
- scope: allow unprivileged delegation on scopes (#2120604)
- udev/net_id: add "rhel-9.1" naming scheme (#2121144)
* Mon Aug 22 2022 systemd maintenance team <systemd-maint@redhat.com> - 250-10
- shared/install: fix crash when reenable is called without --root (#2120222)