Skip to content

Commit

Permalink
preloadNSS: rework the dns query workaround
Browse files Browse the repository at this point in the history
backport of NixOS#5384 to nix 2.4
  • Loading branch information
baloo committed Nov 25, 2021
1 parent 015215f commit 1fdd536
Showing 1 changed file with 31 additions and 17 deletions.
48 changes: 31 additions & 17 deletions src/libmain/shared.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#ifdef __linux__
#include <features.h>
#endif
#ifdef __GLIBC__
#include <gnu/lib-names.h>
#include <nss.h>
#include <dlfcn.h>
#endif

#include <openssl/crypto.h>

Expand Down Expand Up @@ -121,21 +126,30 @@ static void preloadNSS() {
been loaded in the parent. So we force a lookup of an invalid domain to force the NSS machinery to
load its lookup libraries in the parent before any child gets a chance to. */
std::call_once(dns_resolve_flag, []() {
struct addrinfo *res = NULL;

/* nss will only force the "local" (not through nscd) dns resolution if its on the LOCALDOMAIN.
We need the resolution to be done locally, as nscd socket will not be accessible in the
sandbox. */
char * previous_env = getenv("LOCALDOMAIN");
setenv("LOCALDOMAIN", "invalid", 1);
if (getaddrinfo("this.pre-initializes.the.dns.resolvers.invalid.", "http", NULL, &res) == 0) {
if (res) freeaddrinfo(res);
}
if (previous_env) {
setenv("LOCALDOMAIN", previous_env, 1);
} else {
unsetenv("LOCALDOMAIN");
#ifdef __GLIBC__
/* On linux, glibc will run every lookup through the nss layer.
* That means every lookup goes, by default, through nscd, which acts as a local
* cache.
* Because we run builds in a sandbox, we also remove access to nscd otherwise
* lookups would leak into the sandbox.
*
* But now we have a new problem, we need to make sure the nss_dns backend that
* does the dns lookups when nscd is not available is loaded or available.
*
* We can't make it available without leaking nix's environment, so instead we'll
* load the backend, and configure nss so it does not try to run dns lookups
* through nscd.
*
* This is technically only used for builtins:fetch* functions so we only care
* about dns.
*
* All other platforms are unaffected.
*/
if (dlopen (LIBNSS_DNS_SO, RTLD_NOW) == NULL) {
printMsg(Verbosity::lvlWarn, fmt("Unable to load nss_dns backend"));
}
__nss_configure_lookup ("hosts", "dns");
#endif
});
}

Expand Down

0 comments on commit 1fdd536

Please sign in to comment.