]> git.proxmox.com Git - systemd.git/blobdiff - src/nss-resolve/nss-resolve.c
New upstream version 240
[systemd.git] / src / nss-resolve / nss-resolve.c
index eb3d2d977f45f42c764389c85ee03e8a5c76e9bb..a28b5d8ba81db5a2bcf52e418649e17efe1d9b04 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,
@@ -108,6 +122,7 @@ enum nss_status _nss_resolve_gethostbyname4_r(
         char *r_name;
         int c, r, i = 0;
 
+        PROTECT_ERRNO;
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
 
         assert(name);
@@ -116,6 +131,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;
@@ -140,20 +160,15 @@ enum nss_status _nss_resolve_gethostbyname4_r(
 
         r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
         if (r < 0) {
-                if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN")) {
-                        *errnop = ESRCH;
-                        *h_errnop = HOST_NOT_FOUND;
-                        return NSS_STATUS_NOTFOUND;
-                }
+                if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN") ||
+                    !bus_error_shall_fallback(&error))
+                        goto not_found;
 
                 /* Return NSS_STATUS_UNAVAIL when communication with systemd-resolved fails,
                    allowing falling back to other nss modules. Treat all other error conditions as
                    NOTFOUND. This includes DNSSEC errors and suchlike. (We don't use UNAVAIL in this
                    case so that the nsswitch.conf configuration can distuingish such executed but
                    negative replies from complete failure to talk to resolved). */
-                if (!bus_error_shall_fallback(&error))
-                        ret = NSS_STATUS_NOTFOUND;
-
                 goto fail;
         }
 
@@ -162,11 +177,8 @@ enum nss_status _nss_resolve_gethostbyname4_r(
                 r = c;
                 goto fail;
         }
-        if (c == 0) {
-                *errnop = ESRCH;
-                *h_errnop = HOST_NOT_FOUND;
-                return NSS_STATUS_NOTFOUND;
-        }
+        if (c == 0)
+                goto not_found;
 
         if (isempty(canonical))
                 canonical = name;
@@ -247,8 +259,8 @@ enum nss_status _nss_resolve_gethostbyname4_r(
         if (ttlp)
                 *ttlp = 0;
 
-        /* Explicitly reset all error variables */
-        *errnop = 0;
+        /* Explicitly reset both *h_errnop and h_errno to work around
+         * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
         *h_errnop = NETDB_SUCCESS;
         h_errno = 0;
 
@@ -258,6 +270,10 @@ fail:
         *errnop = -r;
         *h_errnop = NO_RECOVERY;
         return ret;
+
+not_found:
+        *h_errnop = HOST_NOT_FOUND;
+        return NSS_STATUS_NOTFOUND;
 }
 
 enum nss_status _nss_resolve_gethostbyname3_r(
@@ -278,6 +294,7 @@ enum nss_status _nss_resolve_gethostbyname3_r(
         const char *canonical;
         int c, r, i = 0;
 
+        PROTECT_ERRNO;
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
 
         assert(name);
@@ -294,6 +311,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;
@@ -318,14 +340,9 @@ enum nss_status _nss_resolve_gethostbyname3_r(
 
         r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
         if (r < 0) {
-                if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN")) {
-                        *errnop = ESRCH;
-                        *h_errnop = HOST_NOT_FOUND;
-                        return NSS_STATUS_NOTFOUND;
-                }
-
-                if (!bus_error_shall_fallback(&error))
-                        ret = NSS_STATUS_NOTFOUND;
+                if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN") ||
+                    !bus_error_shall_fallback(&error))
+                        goto not_found;
 
                 goto fail;
         }
@@ -335,11 +352,8 @@ enum nss_status _nss_resolve_gethostbyname3_r(
                 r = c;
                 goto fail;
         }
-        if (c == 0) {
-                *errnop = ESRCH;
-                *h_errnop = HOST_NOT_FOUND;
-                return NSS_STATUS_NOTFOUND;
-        }
+        if (c == 0)
+                goto not_found;
 
         if (isempty(canonical))
                 canonical = name;
@@ -427,23 +441,27 @@ enum nss_status _nss_resolve_gethostbyname3_r(
         result->h_length = alen;
         result->h_addr_list = (char**) r_addr_list;
 
-        /* Explicitly reset all error variables */
-        *errnop = 0;
-        *h_errnop = NETDB_SUCCESS;
-        h_errno = 0;
-
         if (ttlp)
                 *ttlp = 0;
 
         if (canonp)
                 *canonp = r_name;
 
+        /* Explicitly reset both *h_errnop and h_errno to work around
+         * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
+        *h_errnop = NETDB_SUCCESS;
+        h_errno = 0;
+
         return NSS_STATUS_SUCCESS;
 
 fail:
         *errnop = -r;
         *h_errnop = NO_RECOVERY;
         return ret;
+
+not_found:
+        *h_errnop = HOST_NOT_FOUND;
+        return NSS_STATUS_NOTFOUND;
 }
 
 enum nss_status _nss_resolve_gethostbyaddr2_r(
@@ -464,6 +482,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
         const char *n;
         int r, ifindex;
 
+        PROTECT_ERRNO;
         BLOCK_SIGNALS(NSS_SIGNALS_BLOCK);
 
         assert(addr);
@@ -484,6 +503,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;
@@ -516,14 +540,9 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
 
         r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
         if (r < 0) {
-                if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN")) {
-                        *errnop = ESRCH;
-                        *h_errnop = HOST_NOT_FOUND;
-                        return NSS_STATUS_NOTFOUND;
-                }
-
-                if (!bus_error_shall_fallback(&error))
-                        ret = NSS_STATUS_NOTFOUND;
+                if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN") ||
+                    !bus_error_shall_fallback(&error))
+                        goto not_found;
 
                 goto fail;
         }
@@ -549,11 +568,8 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
         if (r < 0)
                 return r;
 
-        if (c <= 0) {
-                *errnop = ESRCH;
-                *h_errnop = HOST_NOT_FOUND;
-                return NSS_STATUS_NOTFOUND;
-        }
+        if (c <= 0)
+                goto not_found;
 
         ms += ALIGN(len) +              /* the address */
               2 * sizeof(char*) +       /* pointers to the address, plus trailing NULL */
@@ -612,8 +628,8 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
         if (ttlp)
                 *ttlp = 0;
 
-        /* Explicitly reset all error variables */
-        *errnop = 0;
+        /* Explicitly reset both *h_errnop and h_errno to work around
+         * https://bugzilla.redhat.com/show_bug.cgi?id=1125975 */
         *h_errnop = NETDB_SUCCESS;
         h_errno = 0;
 
@@ -623,6 +639,10 @@ fail:
         *errnop = -r;
         *h_errnop = NO_RECOVERY;
         return ret;
+
+not_found:
+        *h_errnop = HOST_NOT_FOUND;
+        return NSS_STATUS_NOTFOUND;
 }
 
 NSS_GETHOSTBYNAME_FALLBACKS(resolve);