From 0b42a0f7813ade2bc3114bbf02b49e688e376e42 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Mon, 6 Sep 2021 23:13:27 +0000 Subject: [PATCH 1/2] preloadNSS: fixup nss_dns load Before this commit, the dns lookup in preloadNSS would still go through nscd. This did not have the effect of loading the nss_dns.so as expected (nss_dns.so being out of reach from within the sandbox). Should LOCALDOMAIN environment variable be defined, nss will completely avoid nscd and will do its dns resolution on its own. By temporarly setting LOCALDOMAIN variable before calling in NSS, we can force NSS to load the shared libraries as expected. Fixes #5089 Signed-off-by: Arthur Gautier --- src/libstore/build/local-derivation-goal.cc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc index 990ff60b7..2dcbedd4a 100644 --- a/src/libstore/build/local-derivation-goal.cc +++ b/src/libstore/build/local-derivation-goal.cc @@ -354,9 +354,19 @@ static void preloadNSS() { std::call_once(dns_resolve_flag, []() { struct addrinfo *res = NULL; - if (getaddrinfo("this.pre-initializes.the.dns.resolvers.invalid.", "http", NULL, &res) != 0) { + /* 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"); + } }); } From 3b72741f23a854d351db8c1d76a74c9255141873 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Wed, 8 Sep 2021 18:11:43 +0000 Subject: [PATCH 2/2] preloadNSS: load NSS before threads are started preloadNSS is not thread-safe, this commit moves it before we start the first thread. Signed-off-by: Arthur Gautier --- src/libmain/shared.cc | 30 ++++++++++++++++++ src/libstore/build/local-derivation-goal.cc | 34 --------------------- 2 files changed, 30 insertions(+), 34 deletions(-) diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index 3a9529c4d..85f9f0d58 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -15,6 +15,9 @@ #include #include #include +#include +#include +#include #include @@ -110,6 +113,31 @@ static void opensslLockCallback(int mode, int type, const char * file, int line) } #endif +static std::once_flag dns_resolve_flag; + +static void preloadNSS() { + /* builtin:fetchurl can trigger a DNS lookup, which with glibc can trigger a dynamic library load of + one of the glibc NSS libraries in a sandboxed child, which will fail unless the library's already + 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"); + } + }); +} static void sigHandler(int signo) { } @@ -176,6 +204,8 @@ void initNix() if (hasPrefix(getEnv("TMPDIR").value_or("/tmp"), "/var/folders/")) unsetenv("TMPDIR"); #endif + + preloadNSS(); } diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc index 2dcbedd4a..5cc0691e8 100644 --- a/src/libstore/build/local-derivation-goal.cc +++ b/src/libstore/build/local-derivation-goal.cc @@ -17,10 +17,7 @@ #include #include -#include -#include #include -#include #include #include #include @@ -34,7 +31,6 @@ /* Includes required for chroot support. */ #if __linux__ -#include #include #include #include @@ -344,33 +340,6 @@ int childEntry(void * arg) } -static std::once_flag dns_resolve_flag; - -static void preloadNSS() { - /* builtin:fetchurl can trigger a DNS lookup, which with glibc can trigger a dynamic library load of - one of the glibc NSS libraries in a sandboxed child, which will fail unless the library's already - 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"); - } - }); -} - - static void linkOrCopy(const Path & from, const Path & to) { if (link(from.c_str(), to.c_str()) == -1) { @@ -399,9 +368,6 @@ void LocalDerivationGoal::startBuilder() settings.thisSystem, concatStringsSep(", ", worker.store.systemFeatures)); - if (drv->isBuiltin()) - preloadNSS(); - #if __APPLE__ additionalSandboxProfile = parsedDrv->getStringAttr("__sandboxProfile").value_or(""); #endif