Skip to content

Commit

Permalink
Move preloadNSS() from initNix to initLibStore
Browse files Browse the repository at this point in the history
It is required for the sandbox, which is a libstore responsibility;
not just libmain.
  • Loading branch information
roberth committed Feb 5, 2023
1 parent 26e15bb commit 0992b41
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 42 deletions.
42 changes: 0 additions & 42 deletions src/libmain/shared.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#include <cctype>
#include <exception>
#include <iostream>
#include <mutex>

#include <cstdlib>
#include <sys/time.h>
Expand All @@ -20,11 +19,6 @@
#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 @@ -103,41 +97,6 @@ std::string getArg(const std::string & opt,
return *i;
}

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, []() {
#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))
warn("unable to load nss_dns backend");
// FIXME: get hosts entry from nsswitch.conf.
__nss_configure_lookup("hosts", "files dns");
#endif
});
}

static void sigHandler(int signo) { }


Expand Down Expand Up @@ -208,7 +167,6 @@ void initNix()
unsetenv("TMPDIR");
#endif

preloadNSS();
}


Expand Down
44 changes: 44 additions & 0 deletions src/libstore/globals.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <algorithm>
#include <map>
#include <mutex>
#include <thread>
#include <dlfcn.h>
#include <sys/utsname.h>
Expand All @@ -15,6 +16,11 @@

#include <sodium/core.h>

#ifdef __GLIBC__
#include <gnu/lib-names.h>
#include <nss.h>
#include <dlfcn.h>
#endif

namespace nix {

Expand Down Expand Up @@ -293,6 +299,42 @@ void initPlugins()
settings.pluginFiles.pluginsLoaded = true;
}

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. */
static std::once_flag dns_resolve_flag;

std::call_once(dns_resolve_flag, []() {
#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))
warn("unable to load nss_dns backend");
// FIXME: get hosts entry from nsswitch.conf.
__nss_configure_lookup("hosts", "files dns");
#endif
});
}

static bool initLibStoreDone = false;

void assertLibStoreInitialized() {
Expand All @@ -309,6 +351,8 @@ void initLibStore() {

loadConfFile();

preloadNSS();

initLibStoreDone = true;
}

Expand Down

0 comments on commit 0992b41

Please sign in to comment.