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 18, 2021
1 parent e664795 commit 0da5946
Show file tree
Hide file tree
Showing 12 changed files with 82 additions and 62 deletions.
36 changes: 5 additions & 31 deletions nixos/modules/config/nsswitch.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ with lib;

{
options = {

# NSS modules. Hacky!
# Only works with nscd!
system.nssModules = mkOption {
type = types.listOf types.path;
internal = true;
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,14 +73,11 @@ 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.";
}
# Provide configured NSS modules at a platform-specific path in /run
systemd.tmpfiles.rules = let
glibcPlatform = "${if pkgs.stdenv.hostPlatform.is64bit then "64" else "32"}-${pkgs.glibc.version}";
in [
"L+ /run/nss-modules${glibcPlatform} - - - - ${config.system.nssModules.path}"
];

# Name Service Switch configuration file. Required by the C
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
75 changes: 75 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,75 @@
Add NSS module load path /run/nss-modules${word_size}-${glibc_version}/lib

This comment has been minimized.

Copy link
@flokli

flokli Oct 19, 2021

Author

This patch isn't created by git format-patch, no? That makes it harder to apply it via git am, in case we want to do changes on it.


If this path is not present at runtime, the behaviour of libc is unchanged.

If this path is present:
- Don't use nscd
- Use this load path as a fallback after paths ${glibc.out}/lib and LD_LIBRARY_PATH

On NixOS, this allows ABI-compatible glibc clients to directly load NSS modules
instead of using nscd for name service requests.
nscd has caching bugs and leaks DNS requests across network namespaces.

nscd, if running, will still be used by ABI-incompatible glibc clients.
(Such as 32-bit binaries on a 64-bit host or binaries with older glibc versions.)
This guarantees full backwards compatibility.

On non-NixOS systems, this shouldn't change behaviour, as the path
doesn't exist there.

diff --git a/nscd/nscd_helper.c b/nscd/nscd_helper.c
index 462504d8..65cca10d 100644
--- a/nscd/nscd_helper.c
+++ b/nscd/nscd_helper.c
@@ -169,6 +169,12 @@ open_socket (request_type type, const char *key, size_t keylen)
{
int sock;

+ /* Don't use nscd when the platform-specific NixOS module load path is present */
+#include "../nss/nixos-nss-modules-path.h"

This comment has been minimized.

Copy link
@flokli

flokli Oct 19, 2021

Author

Let's move the include to the top of the file

+ if (access(NIXOS_NSS_MODULES_PATH, F_OK) == 0) {
+ return -1;
+ }
+
sock = __socket (PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
if (sock < 0)
return -1;
diff --git a/nss/nixos-nss-modules-path.h b/nss/nixos-nss-modules-path.h
new file mode 100644
index 00000000..20a5643b
--- /dev/null
+++ b/nss/nixos-nss-modules-path.h
@@ -0,0 +1,3 @@
+#define STR_(x) #x
+#define STR(x) STR_(x)
+#define NIXOS_NSS_MODULES_PATH "/run/nss-modules" STR(__WORDSIZE) "-" STR(__GLIBC__) "." STR(__GLIBC_MINOR__) "/lib/"

This comment has been minimized.

Copy link
@flokli

flokli Oct 19, 2021

Author

We might want to explicitly #include <bits/wordsize.h> and #include <include/features.h> to make it more clear where these constants are coming from.

diff --git a/nss/nss_module.c b/nss/nss_module.c
index 6c5f341f..f5296507 100644
--- a/nss/nss_module.c
+++ b/nss/nss_module.c
@@ -133,6 +133,25 @@ 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) {
+
+#include "nixos-nss-modules-path.h"

This comment has been minimized.

Copy link
@flokli

flokli Oct 19, 2021

Author

Let's move the that include to the top of the file.

+ 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);
}

2 changes: 2 additions & 0 deletions pkgs/development/libraries/glibc/common.nix
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ stdenv.mkDerivation ({
})

./fix-x64-abi.patch

./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 Down

0 comments on commit 0da5946

Please sign in to comment.