Skip to content

Commit

Permalink
nixos/nscd: disable, provide NSS modules globally
Browse files Browse the repository at this point in the history
NSS modules are now globally provided (by providing a `/run/nss-modules`
symlink), similar to how we handle OpenGL drivers.

This removes the need for nscd as a proxy for all NSS requests, and avoids
DNS requests leaking across network namespaces.

While doing this upgrade, existing applications need to be restarted, so
they know how to pick up NSS modules from `/run/nss-modules`.

If you want to defer application restart to a later time, explicitly enable
`nscd` via `services.nscd.enable` until the application restart.

We can mix NSS modules from any version of glibc according to
https://sourceware.org/legacy-ml/libc-help/2016-12/msg00008.html,
so glibc upgrades shouldn't break old userland loading more recent NSS
modules (and most likely, NSS modules are already loaded)

Fixes: NixOS#55276
Fixes: NixOS#135888
Fixes: NixOS#105353
Cc:    NixOS#52411 (comment)
  • Loading branch information
flokli committed Sep 21, 2021
1 parent b5a813e commit b0818ff
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 56 deletions.
30 changes: 30 additions & 0 deletions nixos/doc/manual/from_md/release-notes/rl-2111.section.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,36 @@ Superuser created successfully.
</listitem>
</itemizedlist>
</listitem>
<listitem>
<para>
NSS modules are now globally provided (by a
<literal>/run/nss-modules</literal> symlink), similar to how
we handle OpenGL drivers.
</para>
<para>
This removes the need for nscd as a proxy for all NSS
requests, and avoids DNS requests leaking across network
namespaces.
</para>
<para>
While doing this upgrade, existing applications need to be
restarted, so they know how to pick up NSS modules from
<literal>/run/nss-modules</literal>.
</para>
<para>
If you want to defer application restart to a later time,
explicitly enable <literal>nscd</literal> via
<literal>services.nscd.enable</literal> until the application
restart.
</para>
<para>
We can mix NSS modules from any version of glibc according to
https://sourceware.org/legacy-ml/libc-help/2016-12/msg00008.html,
so future glibc upgrades shouldn’t break old userland loading
more recent NSS modules (and most likely, NSS modules are
already loaded)
</para>
</listitem>
<listitem>
<para>
The
Expand Down
17 changes: 17 additions & 0 deletions nixos/doc/manual/release-notes/rl-2111.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,23 @@ To be able to access the web UI this port needs to be opened in the firewall.
`myhostname`, but before `dns` should use the default priority
- NSS modules which should come after `dns` should use mkAfter.
- NSS modules are now globally provided (by a `/run/nss-modules` symlink),
similar to how we handle OpenGL drivers.
This removes the need for nscd as a proxy for all NSS requests, and avoids
DNS requests leaking across network namespaces.
While doing this upgrade, existing applications need to be restarted, so
they know how to pick up NSS modules from `/run/nss-modules`.
If you want to defer application restart to a later time, explicitly enable
`nscd` via `services.nscd.enable` until the application restart.
We can mix NSS modules from any version of glibc according to
https://sourceware.org/legacy-ml/libc-help/2016-12/msg00008.html,
so future glibc upgrades shouldn't break old userland loading more recent NSS
modules (and most likely, NSS modules are already loaded)
- The [networking.wireless.iwd](options.html#opt-networking.wireless.iwd.enable) module has a new [networking.wireless.iwd.settings](options.html#opt-networking.wireless.iwd.settings) option.
- The [services.syncoid.enable](options.html#opt-services.syncoid.enable) module now properly drops ZFS permissions after usage. Before it delegated permissions to whole pools instead of datasets and didn't clean up after execution. You can manually look this up for your pools by running `zfs allow your-pool-name` and use `zfs unallow syncoid your-pool-name` to clean this up.
Expand Down
50 changes: 13 additions & 37 deletions nixos/modules/config/nsswitch.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,10 @@ with lib;

{
options = {

# NSS modules. Hacky!
# Only works with nscd!
system.nssModules = mkOption {
type = types.listOf types.path;
internal = true;
default = [];
default = [ ];
description = ''
Path containing NSS (Name Service Switch) modules.
This allows several DNS resolution methods to be specified via
Expand All @@ -34,60 +31,40 @@ 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 = [];
default = [ ];
};

group = mkOption {
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 = [];
default = [ ];
};

shadow = mkOption {
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 = [];
default = [ ];
};

hosts = mkOption {
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 = [];
default = [ ];
};

services = mkOption {
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 = [];
default = [ ];
};
};
};
Expand All @@ -97,14 +74,13 @@ 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 /run/nss-modules
# We can mix NSS modules from any version of glibc according to
# https://sourceware.org/legacy-ml/libc-help/2016-12/msg00008.html,
# so glibc upgrades shouldn't break old userland loading more recent NSS
# modules (and most likely, NSS modules are already loaded)
systemd.tmpfiles.rules = [
"L+ /run/nss-modules - - - - ${config.system.nssModules.path}"
];

# Name Service Switch configuration file. Required by the C
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
16 changes: 7 additions & 9 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 @@ -23,11 +22,9 @@ in

enable = mkOption {
type = types.bool;
default = true;
default = false;
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 @@ -48,12 +45,11 @@ in
environment.etc."nscd.conf".text = cfg.config;

systemd.services.nscd =
{ description = "Name Service Cache Daemon";
{
description = "Name Service Cache Daemon";

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 All @@ -67,14 +63,16 @@ in
# files. So prefix the ExecStart command with "!" to prevent systemd
# from dropping privileges early. See ExecStart in systemd.service(5).
serviceConfig =
{ ExecStart = "!@${nscd}/sbin/nscd nscd";
{
ExecStart = "!@${nscd}/sbin/nscd nscd";
Type = "forking";
DynamicUser = true;
RuntimeDirectory = "nscd";
PIDFile = "/run/nscd/nscd.pid";
Restart = "always";
ExecReload =
[ "${nscd}/sbin/nscd --invalidate passwd"
[
"${nscd}/sbin/nscd --invalidate passwd"
"${nscd}/sbin/nscd --invalidate group"
"${nscd}/sbin/nscd --invalidate hosts"
];
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
From 65a211ee3604733dceba13062f956256a573f27c Mon Sep 17 00:00:00 2001
From: Florian Klink <[email protected]>
Date: Sun, 19 Sep 2021 13:26:33 +0200
Subject: [PATCH] nss_module.c: try loading NSS modules from /run/nss-modules
as a fallback

On NixOS, glibc only looks for NSS modules in ${glibc.out}/lib, and what
LD_LIBRARY_PATH is set to.

LD_LIBRARY_PATH is very invasive, so we don't want to set that globally.
We previously worked this around by running nscd with LD_LIBRARY_PATH
set, but nscd has some caching issues, and leak of resolution traffic,
so it's cleaner to have glibc look for NSS modules in an additional
path, that's provided by NixOS.

On non-NixOS distributions, this shouldn't change behaviour, as the path
doesn't exist there.
---
nss/nss_module.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)

diff --git a/nss/nss_module.c b/nss/nss_module.c
index 6c5f341f..44cfc2a4 100644
--- a/nss/nss_module.c
+++ b/nss/nss_module.c
@@ -133,6 +133,22 @@ module_load (struct nss_module *module)
return false;

handle = __libc_dlopen (shlib_name);
+
+ /* After loading from the default locations, try loading from
+ /run/nss-modules, to allow loading NixOS-provided NSS modules. */
+ if(handle == NULL)
+ {
+ const char *nix_glibc_nss_path = "/run/nss-modules/";
+ char shlib_path[1024];
+ size_t shlib_pathlen = strlen(nix_glibc_nss_path) + strlen(shlib_name);
+
+ if (shlib_pathlen < sizeof (shlib_path))
+ {
+ __stpcpy (__stpcpy (&shlib_path[0], nix_glibc_nss_path), shlib_name);
+ handle = __libc_dlopen (shlib_path);
+ }
+ }
+
free (shlib_name);
}

--
2.32.0

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

./0001-nss_module.c-try-loading-NSS-modules-from-run-nss-mo.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 b0818ff

Please sign in to comment.