!735 fix nss deadlock between dbus-daemon and PID 1
From: @zhang-yao-2022 Reviewed-by: @shenyangyang01 Signed-off-by: @shenyangyang01
This commit is contained in:
commit
8cd2917618
@ -0,0 +1,160 @@
|
||||
From 9d3aec2603e9d10889797f1412fafd16c25a4920 Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Thu, 17 Feb 2022 14:40:25 +0100
|
||||
Subject: [PATCH] pid1: lookup owning PID of BusName= name of services
|
||||
asynchronously
|
||||
|
||||
A first step of removing blocking calls to the D-Bus broker from PID 1.
|
||||
There's a lot more to got (i.e. grep src/core/ for sd_bus_creds
|
||||
basically), but it's a start.
|
||||
|
||||
Removing blocking calls to D-Bus broker deals systematicallly with
|
||||
deadlocks caused by dbus-daemon blocking on synchronous IPC calls back
|
||||
to PID1 (e.g. Varlink calls through nss-systemd). Bugs such as #15316.
|
||||
|
||||
Also-see: https://github.com/systemd/systemd/pull/22038#issuecomment-1042958390
|
||||
(cherry picked from commit e39eb045a502d599e6cd3fda7a46020dd438d018)
|
||||
(cherry picked from commit cf390149cb25248169c482e315a1a7ff02eaf956)
|
||||
|
||||
Conflict:NA
|
||||
Reference:https://github.com/systemd/systemd/commit/1daa382a7f9e55d11f7b59b144a9963688169843
|
||||
---
|
||||
src/core/service.c | 91 ++++++++++++++++++++++++++++++++++++----------
|
||||
src/core/service.h | 2 +
|
||||
2 files changed, 74 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/src/core/service.c b/src/core/service.c
|
||||
index 4cada77..2e3720b 100644
|
||||
--- a/src/core/service.c
|
||||
+++ b/src/core/service.c
|
||||
@@ -407,6 +407,8 @@ static void service_done(Unit *u) {
|
||||
s->timer_event_source = sd_event_source_unref(s->timer_event_source);
|
||||
s->exec_fd_event_source = sd_event_source_unref(s->exec_fd_event_source);
|
||||
|
||||
+ s->bus_name_pid_lookup_slot = sd_bus_slot_unref(s->bus_name_pid_lookup_slot);
|
||||
+
|
||||
service_release_resources(u);
|
||||
}
|
||||
|
||||
@@ -4079,6 +4081,60 @@ static int service_get_timeout(Unit *u, usec_t *timeout) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
+static bool pick_up_pid_from_bus_name(Service *s) {
|
||||
+ assert(s);
|
||||
+
|
||||
+ /* If the service is running but we have no main PID yet, get it from the owner of the D-Bus name */
|
||||
+
|
||||
+ return !pid_is_valid(s->main_pid) &&
|
||||
+ IN_SET(s->state,
|
||||
+ SERVICE_START,
|
||||
+ SERVICE_START_POST,
|
||||
+ SERVICE_RUNNING,
|
||||
+ SERVICE_RELOAD);
|
||||
+}
|
||||
+
|
||||
+static int bus_name_pid_lookup_callback(sd_bus_message *reply, void *userdata, sd_bus_error *ret_error) {
|
||||
+ const sd_bus_error *e;
|
||||
+ Unit *u = userdata;
|
||||
+ uint32_t pid;
|
||||
+ Service *s;
|
||||
+ int r;
|
||||
+
|
||||
+ assert(reply);
|
||||
+ assert(u);
|
||||
+
|
||||
+ s = SERVICE(u);
|
||||
+ s->bus_name_pid_lookup_slot = sd_bus_slot_unref(s->bus_name_pid_lookup_slot);
|
||||
+
|
||||
+ if (!s->bus_name || !pick_up_pid_from_bus_name(s))
|
||||
+ return 1;
|
||||
+
|
||||
+ e = sd_bus_message_get_error(reply);
|
||||
+ if (e) {
|
||||
+ r = sd_bus_error_get_errno(e);
|
||||
+ log_warning_errno(r, "GetConnectionUnixProcessID() failed: %s", bus_error_message(e, r));
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ r = sd_bus_message_read(reply, "u", &pid);
|
||||
+ if (r < 0) {
|
||||
+ bus_log_parse_error(r);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ if (!pid_is_valid(pid)) {
|
||||
+ log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "GetConnectionUnixProcessID() returned invalid PID");
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ log_unit_debug(u, "D-Bus name %s is now owned by process " PID_FMT, s->bus_name, (pid_t) pid);
|
||||
+
|
||||
+ service_set_main_pid(s, pid);
|
||||
+ unit_watch_pid(UNIT(s), pid, false);
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
static void service_bus_name_owner_change(Unit *u, const char *new_owner) {
|
||||
|
||||
Service *s = SERVICE(u);
|
||||
@@ -4109,28 +4165,25 @@ static void service_bus_name_owner_change(Unit *u, const char *new_owner) {
|
||||
else if (s->state == SERVICE_START && new_owner)
|
||||
service_enter_start_post(s);
|
||||
|
||||
- } else if (new_owner &&
|
||||
- s->main_pid <= 0 &&
|
||||
- IN_SET(s->state,
|
||||
- SERVICE_START,
|
||||
- SERVICE_START_POST,
|
||||
- SERVICE_RUNNING,
|
||||
- SERVICE_RELOAD)) {
|
||||
-
|
||||
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
- pid_t pid;
|
||||
+ } else if (new_owner && pick_up_pid_from_bus_name(s)) {
|
||||
|
||||
/* Try to acquire PID from bus service */
|
||||
|
||||
- r = sd_bus_get_name_creds(u->manager->api_bus, s->bus_name, SD_BUS_CREDS_PID, &creds);
|
||||
- if (r >= 0)
|
||||
- r = sd_bus_creds_get_pid(creds, &pid);
|
||||
- if (r >= 0) {
|
||||
- log_unit_debug(u, "D-Bus name %s is now owned by process " PID_FMT, s->bus_name, pid);
|
||||
-
|
||||
- service_set_main_pid(s, pid);
|
||||
- unit_watch_pid(UNIT(s), pid, false);
|
||||
- }
|
||||
+ s->bus_name_pid_lookup_slot = sd_bus_slot_unref(s->bus_name_pid_lookup_slot);
|
||||
+
|
||||
+ r = sd_bus_call_method_async(
|
||||
+ u->manager->api_bus,
|
||||
+ &s->bus_name_pid_lookup_slot,
|
||||
+ "org.freedesktop.DBus",
|
||||
+ "/org/freedesktop/DBus",
|
||||
+ "org.freedesktop.DBus",
|
||||
+ "GetConnectionUnixProcessID",
|
||||
+ bus_name_pid_lookup_callback,
|
||||
+ s,
|
||||
+ "s",
|
||||
+ s->bus_name);
|
||||
+ if (r < 0)
|
||||
+ log_debug_errno(r, "Failed to request owner PID of service name, ignoring: %m");
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/core/service.h b/src/core/service.h
|
||||
index 11e861a..04809e9 100644
|
||||
--- a/src/core/service.h
|
||||
+++ b/src/core/service.h
|
||||
@@ -174,6 +174,8 @@ struct Service {
|
||||
NotifyAccess notify_access;
|
||||
NotifyState notify_state;
|
||||
|
||||
+ sd_bus_slot *bus_name_pid_lookup_slot;
|
||||
+
|
||||
sd_event_source *exec_fd_event_source;
|
||||
|
||||
ServiceFDStore *fd_store;
|
||||
--
|
||||
2.33.0
|
||||
|
||||
@ -0,0 +1,125 @@
|
||||
From 0863a55ae95fe6bf7312b7a864d07a9e3fbee563 Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Thu, 17 Feb 2022 14:49:54 +0100
|
||||
Subject: [PATCH] pid1: set SYSTEMD_NSS_DYNAMIC_BYPASS=1 env var for
|
||||
dbus-daemon
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
There's currently a deadlock between PID 1 and dbus-daemon: in some
|
||||
cases dbus-daemon will do NSS lookups (which are blocking) at the same
|
||||
time PID 1 synchronously blocks on some call to dbus-daemon. Let's break
|
||||
that by setting SYSTEMD_NSS_DYNAMIC_BYPASS=1 env var for dbus-daemon,
|
||||
which will disable synchronously blocking varlink calls from nss-systemd
|
||||
to PID 1.
|
||||
|
||||
In the long run we should fix this differently: remove all synchronous
|
||||
calls to dbus-daemon from PID 1. This is not trivial however: so far we
|
||||
had the rule that synchronous calls from PID 1 to the dbus broker are OK
|
||||
as long as they only go to interfaces implemented by the broke itself
|
||||
rather than services reachable through it. Given that the relationship
|
||||
between PID 1 and dbus is kinda special anyway, this was considered
|
||||
acceptable for the sake of simplicity, since we quite often need
|
||||
metadata about bus peers from the broker, and the asynchronous logic
|
||||
would substantially complicate even the simplest method handlers.
|
||||
|
||||
This mostly reworks the existing code that sets SYSTEMD_NSS_BYPASS_BUS=
|
||||
(which is a similar hack to deal with deadlocks between nss-systemd and
|
||||
dbus-daemon itself) to set SYSTEMD_NSS_DYNAMIC_BYPASS=1 instead. No code
|
||||
was checking SYSTEMD_NSS_BYPASS_BUS= anymore anyway, and it used to
|
||||
solve a similar problem, hence it's an obvious piece of code to rework
|
||||
like this.
|
||||
|
||||
Issue originally tracked down by Lukas Märdian. This patch is inspired
|
||||
and closely based on his patch:
|
||||
|
||||
https://github.com/systemd/systemd/pull/22038
|
||||
|
||||
Fixes: #15316
|
||||
Co-authored-by: Lukas Märdian <slyon@ubuntu.com>
|
||||
(cherry picked from commit de90700f36f2126528f7ce92df0b5b5d5e277558)
|
||||
(cherry picked from commit 367041af816d48d4852140f98fd0ba78ed83f9e4)
|
||||
|
||||
Conflict:different code contexts, manual synchronization patch
|
||||
Reference:https://github.com/systemd/systemd/commit/0863a55ae95fe6bf7312b7a864d07a9e3fbee563
|
||||
---
|
||||
src/core/execute.c | 10 +++++-----
|
||||
src/core/execute.h | 26 +++++++++++++-------------
|
||||
src/core/service.c | 2 +-
|
||||
3 files changed, 19 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/src/core/execute.c b/src/core/execute.c
|
||||
index 28efe5c36f..37f63a9378 100644
|
||||
--- a/src/core/execute.c
|
||||
+++ b/src/core/execute.c
|
||||
@@ -1828,11 +1828,11 @@ static int build_environment(
|
||||
our_env[n_env++] = x;
|
||||
}
|
||||
|
||||
- /* If this is D-Bus, tell the nss-systemd module, since it relies on being able to use D-Bus look up dynamic
|
||||
- * users via PID 1, possibly dead-locking the dbus daemon. This way it will not use D-Bus to resolve names, but
|
||||
- * check the database directly. */
|
||||
- if (p->flags & EXEC_NSS_BYPASS_BUS) {
|
||||
- x = strdup("SYSTEMD_NSS_BYPASS_BUS=1");
|
||||
+ /* If this is D-Bus, tell the nss-systemd module, since it relies on being able to use blocking
|
||||
+ * Varlink calls back to us for look up dynamic users in PID 1. Break the deadlock between D-Bus and
|
||||
+ * PID 1 by disabling use of PID1' NSS interface for looking up dynamic users. */
|
||||
+ if (p->flags & EXEC_NSS_DYNAMIC_BYPASS) {
|
||||
+ x = strdup("SYSTEMD_NSS_DYNAMIC_BYPASS=1");
|
||||
if (!x)
|
||||
return -ENOMEM;
|
||||
our_env[n_env++] = x;
|
||||
diff --git a/src/core/execute.h b/src/core/execute.h
|
||||
index 4c7a5b874f..47349a69a2 100644
|
||||
--- a/src/core/execute.h
|
||||
+++ b/src/core/execute.h
|
||||
@@ -297,20 +297,20 @@ static inline bool exec_context_restrict_namespaces_set(const ExecContext *c) {
|
||||
}
|
||||
|
||||
typedef enum ExecFlags {
|
||||
- EXEC_APPLY_SANDBOXING = 1 << 0,
|
||||
- EXEC_APPLY_CHROOT = 1 << 1,
|
||||
- EXEC_APPLY_TTY_STDIN = 1 << 2,
|
||||
- EXEC_PASS_LOG_UNIT = 1 << 3, /* Whether to pass the unit name to the service's journal stream connection */
|
||||
- EXEC_CHOWN_DIRECTORIES = 1 << 4, /* chown() the runtime/state/cache/log directories to the user we run as, under all conditions */
|
||||
- EXEC_NSS_BYPASS_BUS = 1 << 5, /* Set the SYSTEMD_NSS_BYPASS_BUS environment variable, to disable nss-systemd for dbus */
|
||||
- EXEC_CGROUP_DELEGATE = 1 << 6,
|
||||
- EXEC_IS_CONTROL = 1 << 7,
|
||||
- EXEC_CONTROL_CGROUP = 1 << 8, /* Place the process not in the indicated cgroup but in a subcgroup '/.control', but only EXEC_CGROUP_DELEGATE and EXEC_IS_CONTROL is set, too */
|
||||
+ EXEC_APPLY_SANDBOXING = 1 << 0,
|
||||
+ EXEC_APPLY_CHROOT = 1 << 1,
|
||||
+ EXEC_APPLY_TTY_STDIN = 1 << 2,
|
||||
+ EXEC_PASS_LOG_UNIT = 1 << 3, /* Whether to pass the unit name to the service's journal stream connection */
|
||||
+ EXEC_CHOWN_DIRECTORIES = 1 << 4, /* Set the SYSTEMD_NSS_DYNAMIC_BYPASS environment variable, to disable nss-systemd blocking on PID 1, for use by dbus-daemon */
|
||||
+ EXEC_NSS_DYNAMIC_BYPASS = 1 << 5, /* Set the EXEC_NSS_DYNAMIC_BYPASS environment variable, to disable nss-systemd for dbus */
|
||||
+ EXEC_CGROUP_DELEGATE = 1 << 6,
|
||||
+ EXEC_IS_CONTROL = 1 << 7,
|
||||
+ EXEC_CONTROL_CGROUP = 1 << 8, /* Place the process not in the indicated cgroup but in a subcgroup '/.control', but only EXEC_CGROUP_DELEGATE and EXEC_IS_CONTROL is set, too */
|
||||
|
||||
/* The following are not used by execute.c, but by consumers internally */
|
||||
- EXEC_PASS_FDS = 1 << 9,
|
||||
- EXEC_SETENV_RESULT = 1 << 10,
|
||||
- EXEC_SET_WATCHDOG = 1 << 11,
|
||||
+ EXEC_PASS_FDS = 1 << 9,
|
||||
+ EXEC_SETENV_RESULT = 1 << 10,
|
||||
+ EXEC_SET_WATCHDOG = 1 << 11,
|
||||
} ExecFlags;
|
||||
|
||||
/* Parameters for a specific invocation of a command. This structure is put together right before a command is
|
||||
diff --git a/src/core/service.c b/src/core/service.c
|
||||
index f6eb46cb54..a480edc439 100644
|
||||
--- a/src/core/service.c
|
||||
+++ b/src/core/service.c
|
||||
@@ -1573,7 +1573,7 @@ static int service_spawn(
|
||||
return -ENOMEM;
|
||||
|
||||
/* System D-Bus needs nss-systemd disabled, so that we don't deadlock */
|
||||
- SET_FLAG(exec_params.flags, EXEC_NSS_BYPASS_BUS,
|
||||
+ SET_FLAG(exec_params.flags, EXEC_NSS_DYNAMIC_BYPASS,
|
||||
MANAGER_IS_SYSTEM(UNIT(s)->manager) && unit_has_name(UNIT(s), SPECIAL_DBUS_SERVICE));
|
||||
|
||||
strv_free_and_replace(exec_params.environment, final_env);
|
||||
--
|
||||
2.33.0
|
||||
|
||||
53
backport-pid1-watch-bus-name-always-when-we-have-it.patch
Normal file
53
backport-pid1-watch-bus-name-always-when-we-have-it.patch
Normal file
@ -0,0 +1,53 @@
|
||||
From b301230a6ce52989053b12324fcaef0d45610ee6 Mon Sep 17 00:00:00 2001
|
||||
From: Lennart Poettering <lennart@poettering.net>
|
||||
Date: Thu, 17 Feb 2022 17:23:48 +0100
|
||||
Subject: [PATCH] pid1: watch bus name always when we have it
|
||||
|
||||
Previously we'd only watch configured service bus names if Type=dbus was
|
||||
set. Let's also watch it for other types. This is useful to pick up the
|
||||
main PID of such a service. In fact the code to pick it up was already
|
||||
in place, alas it didn't do anything given the signal was never received
|
||||
for it. Fix that.
|
||||
|
||||
(It's also useful for debugging)
|
||||
|
||||
(cherry picked from commit 1e8b312e5a22538f91defb89cf2997e09e106297)
|
||||
(cherry picked from commit a51e540b278827c0fc59760b9c77cd42cbddc0d2)
|
||||
|
||||
Conflict:different code contexts, manual synchronization patch
|
||||
Reference:https://github.com/systemd/systemd/commit/b301230a6ce52989053b12324fcaef0d45610ee6
|
||||
---
|
||||
src/core/service.c | 18 ++++++++++--------
|
||||
1 file changed, 10 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/src/core/service.c b/src/core/service.c
|
||||
index 7b90822f68..5f56217904 100644
|
||||
--- a/src/core/service.c
|
||||
+++ b/src/core/service.c
|
||||
@@ -697,14 +697,16 @@ static int service_setup_bus_name(Service *s) {
|
||||
if (!s->bus_name)
|
||||
return 0;
|
||||
|
||||
- r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, true, UNIT_DEPENDENCY_FILE);
|
||||
- if (r < 0)
|
||||
- return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m");
|
||||
+ if (s->type == SERVICE_DBUS) {
|
||||
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, true, UNIT_DEPENDENCY_FILE);
|
||||
+ if (r < 0)
|
||||
+ return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m");
|
||||
|
||||
- /* We always want to be ordered against dbus.socket if both are in the transaction. */
|
||||
- r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_DBUS_SOCKET, true, UNIT_DEPENDENCY_FILE);
|
||||
- if (r < 0)
|
||||
- return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m");
|
||||
+ /* We always want to be ordered against dbus.socket if both are in the transaction. */
|
||||
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_DBUS_SOCKET, true, UNIT_DEPENDENCY_FILE);
|
||||
+ if (r < 0)
|
||||
+ return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m");
|
||||
+ }
|
||||
|
||||
r = unit_watch_bus_name(UNIT(s), s->bus_name);
|
||||
if (r == -EEXIST)
|
||||
--
|
||||
2.33.0
|
||||
|
||||
11
systemd.spec
11
systemd.spec
@ -16,7 +16,7 @@
|
||||
Name: systemd
|
||||
Url: https://systemd.io/
|
||||
Version: 243
|
||||
Release: 81
|
||||
Release: 82
|
||||
License: MIT and LGPLv2+ and GPLv2+
|
||||
Summary: System and Service Manager
|
||||
|
||||
@ -308,6 +308,9 @@ Patch0260: backport-CVE-2023-50868.patch
|
||||
Patch0261: backport-login-user-runtime-dir-properly-check-for-mount-poin.patch
|
||||
Patch0262: backport-user-util-validate-the-right-field.patch
|
||||
Patch0263: backport-fix-cgtop-sscanf-return-code-checks.patch
|
||||
Patch0264: backport-pid1-set-SYSTEMD_NSS_DYNAMIC_BYPASS-1-env-var-for-db.patch
|
||||
Patch0265: backport-pid1-lookup-owning-PID-of-BusName-name-of-services-a.patch
|
||||
Patch0266: backport-pid1-watch-bus-name-always-when-we-have-it.patch
|
||||
|
||||
#openEuler
|
||||
Patch9002: 1509-fix-journal-file-descriptors-leak-problems.patch
|
||||
@ -1715,6 +1718,12 @@ fi
|
||||
%exclude /usr/share/man/man3/*
|
||||
|
||||
%changelog
|
||||
* Tue Nov 5 2024 zhangyao <zhangyao108@huawei.com> - 243-82
|
||||
- sync community patches
|
||||
add backport-pid1-set-SYSTEMD_NSS_DYNAMIC_BYPASS-1-env-var-for-db.patch
|
||||
backport-pid1-lookup-owning-PID-of-BusName-name-of-services-a.patch
|
||||
backport-pid1-watch-bus-name-always-when-we-have-it.patch
|
||||
|
||||
* Thu Aug 22 2024 zhangyao <zhangyao108@huawei.com> - 243-81
|
||||
- remove redundant patch
|
||||
del 1610-add-new-rules-for-lower-priority-events-to-preempt.patch
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user