]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
nss: never become IPC clients for services that are about to be started
authorLennart Poettering <lennart@poettering.net>
Wed, 4 Jul 2018 13:37:03 +0000 (15:37 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 20 Jul 2018 14:57:35 +0000 (16:57 +0200)
This is an attempt to automatically detect and avoid certain kinds of
NSS deadlocks as discussed in this thread:

https://lists.freedesktop.org/archives/systemd-devel/2018-July/040975.html

src/nss-mymachines/nss-mymachines.c
src/nss-resolve/nss-resolve.c

index 8d6caa0ada97787aa94b0f78825583d8f48d2497..d56d3b4c214f06bcf5a197b147b6e19a3c3dbc73 100644 (file)
@@ -63,6 +63,20 @@ static int count_addresses(sd_bus_message *m, int af, unsigned *ret) {
         return 0;
 }
 
+static bool avoid_deadlock(void) {
+
+        /* Check whether this lookup might have a chance of deadlocking because we are called from the service manager
+         * code activating systemd-machined.service. After all, we shouldn't synchronously do lookups to
+         * systemd-machined if we are required to finish before it can be started. This of course won't detect all
+         * possible dead locks of this kind, but it should work for the most obvious cases. */
+
+        if (geteuid() != 0) /* Ignore the env vars unless we are privileged. */
+                return false;
+
+        return streq_ptr(getenv("SYSTEMD_ACTIVATION_UNIT"), "systemd-machined.service") &&
+               streq_ptr(getenv("SYSTEMD_ACTIVATION_SCOPE"), "system");
+}
+
 enum nss_status _nss_mymachines_gethostbyname4_r(
                 const char *name,
                 struct gaih_addrtuple **pat,
@@ -102,6 +116,11 @@ enum nss_status _nss_mymachines_gethostbyname4_r(
                 goto fail;
         }
 
+        if (avoid_deadlock()) {
+                r = -EDEADLK;
+                goto fail;
+        }
+
         r = sd_bus_open_system(&bus);
         if (r < 0)
                 goto fail;
@@ -254,6 +273,11 @@ enum nss_status _nss_mymachines_gethostbyname3_r(
                 goto fail;
         }
 
+        if (avoid_deadlock()) {
+                r = -EDEADLK;
+                goto fail;
+        }
+
         r = sd_bus_open_system(&bus);
         if (r < 0)
                 goto fail;
@@ -424,6 +448,11 @@ enum nss_status _nss_mymachines_getpwnam_r(
                  * running on the host. */
                 goto not_found;
 
+        if (avoid_deadlock()) {
+                r = -EDEADLK;
+                goto fail;
+        }
+
         r = sd_bus_open_system(&bus);
         if (r < 0)
                 goto fail;
@@ -505,6 +534,11 @@ enum nss_status _nss_mymachines_getpwuid_r(
         if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
                 goto not_found;
 
+        if (avoid_deadlock()) {
+                r = -EDEADLK;
+                goto fail;
+        }
+
         r = sd_bus_open_system(&bus);
         if (r < 0)
                 goto fail;
@@ -601,6 +635,11 @@ enum nss_status _nss_mymachines_getgrnam_r(
         if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
                 goto not_found;
 
+        if (avoid_deadlock()) {
+                r = -EDEADLK;
+                goto fail;
+        }
+
         r = sd_bus_open_system(&bus);
         if (r < 0)
                 goto fail;
@@ -679,6 +718,11 @@ enum nss_status _nss_mymachines_getgrgid_r(
         if (getenv_bool_secure("SYSTEMD_NSS_BYPASS_BUS") > 0)
                 goto not_found;
 
+        if (avoid_deadlock()) {
+                r = -EDEADLK;
+                goto fail;
+        }
+
         r = sd_bus_open_system(&bus);
         if (r < 0)
                 goto fail;
index eb3d2d977f45f42c764389c85ee03e8a5c76e9bb..f67a28076c1b331011fbf1f7fd804072d33d9437 100644 (file)
@@ -91,6 +91,20 @@ static uint32_t ifindex_to_scopeid(int family, const void *a, int ifindex) {
         return IN6_IS_ADDR_LINKLOCAL(&in6) ? ifindex : 0;
 }
 
+static bool avoid_deadlock(void) {
+
+        /* Check whether this lookup might have a chance of deadlocking because we are called from the service manager
+         * code activating systemd-resolved.service. After all, we shouldn't synchronously do lookups to
+         * systemd-resolved if we are required to finish before it can be started. This of course won't detect all
+         * possible dead locks of this kind, but it should work for the most obvious cases. */
+
+        if (geteuid() != 0) /* Ignore the env vars unless we are privileged. */
+                return false;
+
+        return streq_ptr(getenv("SYSTEMD_ACTIVATION_UNIT"), "systemd-resolved.service") &&
+               streq_ptr(getenv("SYSTEMD_ACTIVATION_SCOPE"), "system");
+}
+
 enum nss_status _nss_resolve_gethostbyname4_r(
                 const char *name,
                 struct gaih_addrtuple **pat,
@@ -116,6 +130,11 @@ enum nss_status _nss_resolve_gethostbyname4_r(
         assert(errnop);
         assert(h_errnop);
 
+        if (avoid_deadlock()) {
+                r = -EDEADLK;
+                goto fail;
+        }
+
         r = sd_bus_open_system(&bus);
         if (r < 0)
                 goto fail;
@@ -294,6 +313,11 @@ enum nss_status _nss_resolve_gethostbyname3_r(
                 goto fail;
         }
 
+        if (avoid_deadlock()) {
+                r = -EDEADLK;
+                goto fail;
+        }
+
         r = sd_bus_open_system(&bus);
         if (r < 0)
                 goto fail;
@@ -484,6 +508,11 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
                 return NSS_STATUS_UNAVAIL;
         }
 
+        if (avoid_deadlock()) {
+                r = -EDEADLK;
+                goto fail;
+        }
+
         r = sd_bus_open_system(&bus);
         if (r < 0)
                 goto fail;