Skip to content

Commit

Permalink
nixos: allow providing NSS modules without nscd
Browse files Browse the repository at this point in the history
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: NixOS#55276
Fixes: NixOS#135888
Fixes: NixOS#105353
Cc:    NixOS#52411 (comment)

Co-authored-by: Erik Arvstedt <[email protected]>
  • Loading branch information
flokli and erikarvstedt committed Oct 23, 2021
1 parent e664795 commit 54da31f
Show file tree
Hide file tree
Showing 12 changed files with 75 additions and 62 deletions.
54 changes: 23 additions & 31 deletions nixos/modules/config/nsswitch.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ''
Expand All @@ -33,10 +30,6 @@ with lib;
type = types.listOf types.str;
description = ''
List of passwd entries to configure in <filename>/etc/nsswitch.conf</filename>.
Note that "files" is always prepended while "systemd" is appended if nscd is enabled.
This option only takes effect if nscd is enabled.
'';
default = [];
};
Expand All @@ -45,10 +38,6 @@ with lib;
type = types.listOf types.str;
description = ''
List of group entries to configure in <filename>/etc/nsswitch.conf</filename>.
Note that "files" is always prepended while "systemd" is appended if nscd is enabled.
This option only takes effect if nscd is enabled.
'';
default = [];
};
Expand All @@ -57,10 +46,6 @@ with lib;
type = types.listOf types.str;
description = ''
List of shadow entries to configure in <filename>/etc/nsswitch.conf</filename>.
Note that "files" is always prepended.
This option only takes effect if nscd is enabled.
'';
default = [];
};
Expand All @@ -69,10 +54,6 @@ with lib;
type = types.listOf types.str;
description = ''
List of hosts entries to configure in <filename>/etc/nsswitch.conf</filename>.
Note that "files" is always prepended, and "dns" and "myhostname" are always appended.
This option only takes effect if nscd is enabled.
'';
default = [];
};
Expand All @@ -81,10 +62,6 @@ with lib;
type = types.listOf types.str;
description = ''
List of services entries to configure in <filename>/etc/nsswitch.conf</filename>.
Note that "files" is always prepended.
This option only takes effect if nscd is enabled.
'';
default = [];
};
Expand All @@ -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 = ''
Expand Down
4 changes: 0 additions & 4 deletions nixos/modules/services/network-filesystems/samba.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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}";

Expand All @@ -44,7 +41,6 @@ let
partOf = [ "samba.target" ];

environment = {
LD_LIBRARY_PATH = nssModulesPath;
LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive";
};

Expand Down
4 changes: 0 additions & 4 deletions nixos/modules/services/networking/avahi-daemon.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
4 changes: 0 additions & 4 deletions nixos/modules/services/networking/ssh/lshd.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 0 additions & 3 deletions nixos/modules/services/networking/ssh/sshd.nix
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ let
cfg = config.services.openssh;
cfgc = config.programs.ssh;

nssModulesPath = config.system.nssModules.path;

userOptions = {

options.openssh.authorizedKeys = {
Expand Down Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion nixos/modules/services/system/dbus.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
8 changes: 0 additions & 8 deletions nixos/modules/services/system/nscd.conf
Original file line number Diff line number Diff line change
@@ -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
Expand Down
5 changes: 0 additions & 5 deletions nixos/modules/services/system/nscd.nix
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ with lib;

let

nssModulesPath = config.system.nssModules.path;
cfg = config.services.nscd;

nscd = if pkgs.stdenv.hostPlatform.libc == "glibc"
Expand All @@ -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.
'';
};

Expand All @@ -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
Expand Down
1 change: 0 additions & 1 deletion nixos/modules/system/boot/resolved.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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]"]);
Expand Down
1 change: 0 additions & 1 deletion nixos/tests/resolv.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down
43 changes: 43 additions & 0 deletions pkgs/development/libraries/glibc/add-extra-module-load-path.patch
Original file line number Diff line number Diff line change
@@ -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);
}

9 changes: 9 additions & 0 deletions pkgs/development/libraries/glibc/common.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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.
Expand Down

0 comments on commit 54da31f

Please sign in to comment.