From 54da31f670250e07428e89fb3e0832712cbaa272 Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Sat, 17 Jul 2021 20:07:15 +0200 Subject: [PATCH] nixos: allow providing NSS modules without nscd NSS modules are now globally provided by a symlink in `/run`. See the description in `add-extra-module-load-path.patch` for further details. Fixes: https://github.com/NixOS/nixpkgs/issues/55276 Fixes: https://github.com/NixOS/nixpkgs/issues/135888 Fixes: https://github.com/NixOS/nixpkgs/issues/105353 Cc: https://github.com/NixOS/nixpkgs/issues/52411#issuecomment-757347201 Co-authored-by: Erik Arvstedt --- nixos/modules/config/nsswitch.nix | 54 ++++++++----------- .../services/network-filesystems/samba.nix | 4 -- .../services/networking/avahi-daemon.nix | 4 -- .../modules/services/networking/ssh/lshd.nix | 4 -- .../modules/services/networking/ssh/sshd.nix | 3 -- nixos/modules/services/system/dbus.nix | 1 - nixos/modules/services/system/nscd.conf | 8 --- nixos/modules/services/system/nscd.nix | 5 -- nixos/modules/system/boot/resolved.nix | 1 - nixos/tests/resolv.nix | 1 - .../glibc/add-extra-module-load-path.patch | 43 +++++++++++++++ pkgs/development/libraries/glibc/common.nix | 9 ++++ 12 files changed, 75 insertions(+), 62 deletions(-) create mode 100644 pkgs/development/libraries/glibc/add-extra-module-load-path.patch diff --git a/nixos/modules/config/nsswitch.nix b/nixos/modules/config/nsswitch.nix index fb45664e44e12..830a111130d98 100644 --- a/nixos/modules/config/nsswitch.nix +++ b/nixos/modules/config/nsswitch.nix @@ -6,11 +6,8 @@ with lib; { options = { - - # NSS modules. Hacky! - # Only works with nscd! system.nssModules = mkOption { - type = types.listOf types.path; + type = types.listOf types.package; internal = true; default = []; description = '' @@ -33,10 +30,6 @@ with lib; type = types.listOf types.str; description = '' List of passwd entries to configure in /etc/nsswitch.conf. - - Note that "files" is always prepended while "systemd" is appended if nscd is enabled. - - This option only takes effect if nscd is enabled. ''; default = []; }; @@ -45,10 +38,6 @@ with lib; type = types.listOf types.str; description = '' List of group entries to configure in /etc/nsswitch.conf. - - Note that "files" is always prepended while "systemd" is appended if nscd is enabled. - - This option only takes effect if nscd is enabled. ''; default = []; }; @@ -57,10 +46,6 @@ with lib; type = types.listOf types.str; description = '' List of shadow entries to configure in /etc/nsswitch.conf. - - Note that "files" is always prepended. - - This option only takes effect if nscd is enabled. ''; default = []; }; @@ -69,10 +54,6 @@ with lib; type = types.listOf types.str; description = '' List of hosts entries to configure in /etc/nsswitch.conf. - - Note that "files" is always prepended, and "dns" and "myhostname" are always appended. - - This option only takes effect if nscd is enabled. ''; default = []; }; @@ -81,10 +62,6 @@ with lib; type = types.listOf types.str; description = '' List of services entries to configure in /etc/nsswitch.conf. - - Note that "files" is always prepended. - - This option only takes effect if nscd is enabled. ''; default = []; }; @@ -96,16 +73,31 @@ with lib; ]; config = { - assertions = [ - { - # Prevent users from disabling nscd, with nssModules being set. - # If disabling nscd is really necessary, it's still possible to opt out - # by forcing config.system.nssModules to []. - assertion = config.system.nssModules.path != "" -> config.services.nscd.enable; - message = "Loading NSS modules from system.nssModules (${config.system.nssModules.path}), requires services.nscd.enable being set to true."; + assertions = let + systemGlibc = pkgs.stdenv.glibc.outPath; + incompatibleModules = builtins.filter (module: module.stdenv.glibc.outPath != systemGlibc) + config.system.nssModules.list; + in [ + { assertion = (incompatibleModules == []); + message = '' + The following NSS modules don't use the system glibc derivation. + They can fail due to ABI incompatibilities. Please remove them: + ${concatMapStringsSep "\n" (builtins.getAttr "name") incompatibleModules} + ''; } ]; + # Provide NSS modules at a glibc-specific path in /run + # See ../../../pkgs/development/libraries/glibc/add-extra-module-load-path.patch + # for further details. + systemd.tmpfiles.rules = let + prefixLen = builtins.stringLength builtins.storeDir + 1; + hashLen = 32; + glibcStorePathHash = builtins.substring prefixLen hashLen pkgs.glibc.outPath; + in [ + "L+ /run/nss-modules-${glibcStorePathHash} - - - - ${config.system.nssModules.path}" + ]; + # Name Service Switch configuration file. Required by the C # library. environment.etc."nsswitch.conf".text = '' diff --git a/nixos/modules/services/network-filesystems/samba.nix b/nixos/modules/services/network-filesystems/samba.nix index 78ea245cb3519..1154b21fdad51 100644 --- a/nixos/modules/services/network-filesystems/samba.nix +++ b/nixos/modules/services/network-filesystems/samba.nix @@ -33,9 +33,6 @@ let ${smbToString (map shareConfig (attrNames cfg.shares))} ''); - # This may include nss_ldap, needed for samba if it has to use ldap. - nssModulesPath = config.system.nssModules.path; - daemonService = appName: args: { description = "Samba Service Daemon ${appName}"; @@ -44,7 +41,6 @@ let partOf = [ "samba.target" ]; environment = { - LD_LIBRARY_PATH = nssModulesPath; LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive"; }; diff --git a/nixos/modules/services/networking/avahi-daemon.nix b/nixos/modules/services/networking/avahi-daemon.nix index 020a817f25961..c58202c1427fb 100644 --- a/nixos/modules/services/networking/avahi-daemon.nix +++ b/nixos/modules/services/networking/avahi-daemon.nix @@ -264,10 +264,6 @@ in wantedBy = [ "multi-user.target" ]; requires = [ "avahi-daemon.socket" ]; - # Make NSS modules visible so that `avahi_nss_support ()' can - # return a sensible value. - environment.LD_LIBRARY_PATH = config.system.nssModules.path; - path = [ pkgs.coreutils pkgs.avahi ]; serviceConfig = { diff --git a/nixos/modules/services/networking/ssh/lshd.nix b/nixos/modules/services/networking/ssh/lshd.nix index 862ff7df05407..e1eba3a7a8f07 100644 --- a/nixos/modules/services/networking/ssh/lshd.nix +++ b/nixos/modules/services/networking/ssh/lshd.nix @@ -137,10 +137,6 @@ in wantedBy = [ "multi-user.target" ]; - environment = { - LD_LIBRARY_PATH = config.system.nssModules.path; - }; - preStart = '' test -d /etc/lsh || mkdir -m 0755 -p /etc/lsh test -d /var/spool/lsh || mkdir -m 0755 -p /var/spool/lsh diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix index 225aee5160503..89adc40379394 100644 --- a/nixos/modules/services/networking/ssh/sshd.nix +++ b/nixos/modules/services/networking/ssh/sshd.nix @@ -24,8 +24,6 @@ let cfg = config.services.openssh; cfgc = config.programs.ssh; - nssModulesPath = config.system.nssModules.path; - userOptions = { options.openssh.authorizedKeys = { @@ -421,7 +419,6 @@ in after = [ "network.target" ]; stopIfChanged = false; path = [ cfgc.package pkgs.gawk ]; - environment.LD_LIBRARY_PATH = nssModulesPath; restartTriggers = optionals (!cfg.startWhenNeeded) [ config.environment.etc."ssh/sshd_config".source diff --git a/nixos/modules/services/system/dbus.nix b/nixos/modules/services/system/dbus.nix index d4cacb85694b9..f7ab64630610b 100644 --- a/nixos/modules/services/system/dbus.nix +++ b/nixos/modules/services/system/dbus.nix @@ -122,7 +122,6 @@ in # Don't restart dbus-daemon. Bad things tend to happen if we do. reloadIfChanged = true; restartTriggers = [ configDir ]; - environment = { LD_LIBRARY_PATH = config.system.nssModules.path; }; }; systemd.user = { diff --git a/nixos/modules/services/system/nscd.conf b/nixos/modules/services/system/nscd.conf index 722b883ba420b..eb9c48ded1266 100644 --- a/nixos/modules/services/system/nscd.conf +++ b/nixos/modules/services/system/nscd.conf @@ -1,11 +1,3 @@ -# We basically use nscd as a proxy for forwarding nss requests to appropriate -# nss modules, as we run nscd with LD_LIBRARY_PATH set to the directory -# containing all such modules -# Note that we can not use `enable-cache no` As this will actually cause nscd -# to just reject the nss requests it receives, which then causes glibc to -# fallback to trying to handle the request by itself. Which won't work as glibc -# is not aware of the path in which the nss modules live. As a workaround, we -# have `enable-cache yes` with an explicit ttl of 0 server-user nscd enable-cache passwd yes diff --git a/nixos/modules/services/system/nscd.nix b/nixos/modules/services/system/nscd.nix index 7d05acfc14b87..1d7229d110753 100644 --- a/nixos/modules/services/system/nscd.nix +++ b/nixos/modules/services/system/nscd.nix @@ -4,7 +4,6 @@ with lib; let - nssModulesPath = config.system.nssModules.path; cfg = config.services.nscd; nscd = if pkgs.stdenv.hostPlatform.libc == "glibc" @@ -26,8 +25,6 @@ in default = true; description = '' Whether to enable the Name Service Cache Daemon. - Disabling this is strongly discouraged, as this effectively disables NSS Lookups - from all non-glibc NSS modules, including the ones provided by systemd. ''; }; @@ -53,8 +50,6 @@ in wantedBy = [ "nss-lookup.target" "nss-user-lookup.target" ]; - environment = { LD_LIBRARY_PATH = nssModulesPath; }; - restartTriggers = [ config.environment.etc.hosts.source config.environment.etc."nsswitch.conf".source diff --git a/nixos/modules/system/boot/resolved.nix b/nixos/modules/system/boot/resolved.nix index a6fc07da0abbf..36f9302a8e86a 100644 --- a/nixos/modules/system/boot/resolved.nix +++ b/nixos/modules/system/boot/resolved.nix @@ -138,7 +138,6 @@ in users.users.systemd-resolve.group = "systemd-resolve"; - # add resolve to nss hosts database if enabled and nscd enabled # system.nssModules is configured in nixos/modules/system/boot/systemd.nix # added with order 501 to allow modules to go before with mkBefore system.nssDatabases.hosts = (mkOrder 501 ["resolve [!UNAVAIL=return]"]); diff --git a/nixos/tests/resolv.nix b/nixos/tests/resolv.nix index f0aa7e42aaf35..5ff9491036bdd 100644 --- a/nixos/tests/resolv.nix +++ b/nixos/tests/resolv.nix @@ -29,7 +29,6 @@ import ./make-test-python.nix ({ pkgs, ... } : { start_all() - resolv.wait_for_unit("nscd") ipv4 = ["192.0.2.1", "192.0.2.2"] ipv6 = ["2001:db8::2:1", "2001:db8::2:2"] diff --git a/pkgs/development/libraries/glibc/add-extra-module-load-path.patch b/pkgs/development/libraries/glibc/add-extra-module-load-path.patch new file mode 100644 index 0000000000000..aee96449e755a --- /dev/null +++ b/pkgs/development/libraries/glibc/add-extra-module-load-path.patch @@ -0,0 +1,43 @@ +Add NSS module load path /run/nss-modules-${glibc-store-path-hash} as a +fallback. Previously, glibc only looked for NSS modules in ${glibc.out}/lib and +LD_LIBRARY_PATH. + +When this path is provided by NixOS, glibc binaries can be run without nscd. +nscd has caching bugs and leaks DNS requests across network namespaces. +Also, it's no longer required to set LD_LIBRARY_PATH for NSS modules that can't +be proxied by nscd. + +The module load path is only used by binaries that use the same glibc +derivation as the NSS modules. Loading different glibc instances into a +single process would lead to failures due to ABI incompatibilities. + +On non-NixOS systems, this patch doesn't change behaviour, as the path +doesn't exist there. +diff --git a/nss/nss_module.c b/nss/nss_module.c +index 6c5f341f..a9975dd6 100644 +--- a/nss/nss_module.c ++++ b/nss/nss_module.c +@@ -133,6 +133,23 @@ module_load (struct nss_module *module) + return false; + + handle = __libc_dlopen (shlib_name); ++ ++ /* After loading from the default locations, try loading from ++ the NixOS module load path. */ ++ if (handle == NULL) { ++ const char nix_nss_path[] = "@NIXOS_NSS_MODULES_PATH@"; ++ char shlib_path[1024]; ++ size_t nix_nss_path_len = sizeof(nix_nss_path) - 1; ++ size_t shlib_name_len = strlen(shlib_name); ++ size_t shlib_path_len = nix_nss_path_len + shlib_name_len; ++ ++ if (shlib_path_len < sizeof(shlib_path)) { ++ memcpy(&shlib_path[0], nix_nss_path, nix_nss_path_len); ++ memcpy(&shlib_path[nix_nss_path_len], shlib_name, shlib_name_len + 1); ++ handle = __libc_dlopen(shlib_path); ++ } ++ } ++ + free (shlib_name); + } + diff --git a/pkgs/development/libraries/glibc/common.nix b/pkgs/development/libraries/glibc/common.nix index e651a8effac99..ea9acfc25a5e5 100644 --- a/pkgs/development/libraries/glibc/common.nix +++ b/pkgs/development/libraries/glibc/common.nix @@ -120,6 +120,9 @@ stdenv.mkDerivation ({ }) ./fix-x64-abi.patch + + # This patch requires additional processing in postPatch + ./add-extra-module-load-path.patch ] ++ lib.optional stdenv.hostPlatform.isMusl ./fix-rpc-types-musl-conflicts.patch ++ lib.optional stdenv.buildPlatform.isDarwin ./darwin-cross-build.patch; @@ -133,6 +136,12 @@ stdenv.mkDerivation ({ # nscd needs libgcc, and we don't want it dynamically linked # because we don't want it to depend on bootstrap-tools libs. echo "LDFLAGS-nscd += -static-libgcc" >> nscd/Makefile + + # Required by ./add-extra-module-load-path.patch + [[ $out =~ /nix/store/([^-]+) ]] + storePathHash=''${BASH_REMATCH[1]} + nssModulesPath=/run/nss-modules-$storePathHash/lib/ + sed -i "s|@NIXOS_NSS_MODULES_PATH@|$nssModulesPath|g" nss/nss_module.c '' # FIXME: find a solution for infinite recursion in cross builds. # For now it's hopefully acceptable that IDN from libc doesn't reliably work.