diff --git a/nixos/doc/manual/release-notes/rl-1703.xml b/nixos/doc/manual/release-notes/rl-1703.xml index 51de93db92f..8f9694bad8b 100644 --- a/nixos/doc/manual/release-notes/rl-1703.xml +++ b/nixos/doc/manual/release-notes/rl-1703.xml @@ -16,6 +16,11 @@ has the following highlights: manual for more information. + + The setuid wrapper functionality now supports setting + capabilities. + + X.org server uses branch 1.19. Due to ABI incompatibilities, ati_unfree keeps forcing 1.17 diff --git a/nixos/modules/config/shells-environment.nix b/nixos/modules/config/shells-environment.nix index 8147fed39d0..8a7b3ea0bfd 100644 --- a/nixos/modules/config/shells-environment.nix +++ b/nixos/modules/config/shells-environment.nix @@ -168,7 +168,7 @@ in ${cfg.extraInit} - # The setuid wrappers override other bin directories. + # The setuid/setcap wrappers override other bin directories. export PATH="${config.security.wrapperDir}:$PATH" # ~/bin if it exists overrides other bin directories. diff --git a/nixos/modules/installer/tools/nixos-generate-config.pl b/nixos/modules/installer/tools/nixos-generate-config.pl index 48f6cc76e4a..b72db1f6f50 100644 --- a/nixos/modules/installer/tools/nixos-generate-config.pl +++ b/nixos/modules/installer/tools/nixos-generate-config.pl @@ -347,7 +347,6 @@ foreach my $fs (read_file("/proc/self/mountinfo")) { # Skip special filesystems. next if in($mountPoint, "/proc") || in($mountPoint, "/dev") || in($mountPoint, "/sys") || in($mountPoint, "/run") || $mountPoint eq "/var/lib/nfs/rpc_pipefs"; - next if $mountPoint eq "/var/setuid-wrappers"; # Skip the optional fields. my $n = 6; $n++ while $fields[$n] ne "-"; $n++; diff --git a/nixos/modules/installer/tools/nixos-install.sh b/nixos/modules/installer/tools/nixos-install.sh index da28c027c56..57bc249360e 100644 --- a/nixos/modules/installer/tools/nixos-install.sh +++ b/nixos/modules/installer/tools/nixos-install.sh @@ -259,9 +259,9 @@ chroot $mountPoint /nix/var/nix/profiles/system/activate # Ask the user to set a root password. -if [ -z "$noRootPasswd" ] && chroot $mountPoint [ -x /var/setuid-wrappers/passwd ] && [ -t 0 ]; then +if [ -z "$noRootPasswd" ] && chroot $mountPoint [ -x /run/wrappers/bin/passwd ] && [ -t 0 ]; then echo "setting root password..." - chroot $mountPoint /var/setuid-wrappers/passwd + chroot $mountPoint /run/wrappers/bin/passwd fi diff --git a/nixos/modules/misc/locate.nix b/nixos/modules/misc/locate.nix index a9c84f6db24..089f354f611 100644 --- a/nixos/modules/misc/locate.nix +++ b/nixos/modules/misc/locate.nix @@ -103,15 +103,16 @@ in { config = mkIf cfg.enable { users.extraGroups = mkIf isMLocate { mlocate = {}; }; - security.setuidOwners = mkIf isMLocate - [ { group = "mlocate"; - owner = "root"; - permissions = "u+rx,g+x,o+x"; - setgid = true; - setuid = false; - program = "locate"; - } - ]; + security.wrappers = mkIf isMLocate { + mlocate = { + group = "mlocate"; + owner = "root"; + permissions = "u+rx,g+x,o+x"; + setgid = true; + setuid = false; + program = "locate"; + }; + }; nixpkgs.config = { locate.dbfile = cfg.output; }; diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index cf791a67f53..81597d91d89 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -113,7 +113,7 @@ ./security/prey.nix ./security/rngd.nix ./security/rtkit.nix - ./security/setuid-wrappers.nix + ./security/wrappers/default.nix ./security/sudo.nix ./services/amqp/activemq/default.nix ./services/amqp/rabbitmq.nix diff --git a/nixos/modules/programs/kbdlight.nix b/nixos/modules/programs/kbdlight.nix index 0172368e968..58e45872fac 100644 --- a/nixos/modules/programs/kbdlight.nix +++ b/nixos/modules/programs/kbdlight.nix @@ -11,6 +11,6 @@ in config = mkIf cfg.enable { environment.systemPackages = [ pkgs.kbdlight ]; - security.setuidPrograms = [ "kbdlight" ]; + security.wrappers.kbdlight.source = "${pkgs.kbdlight.out}/bin/kbdlight"; }; } diff --git a/nixos/modules/programs/light.nix b/nixos/modules/programs/light.nix index 09cd1113d9c..6f8c389acc9 100644 --- a/nixos/modules/programs/light.nix +++ b/nixos/modules/programs/light.nix @@ -21,6 +21,6 @@ in config = mkIf cfg.enable { environment.systemPackages = [ pkgs.light ]; - security.setuidPrograms = [ "light" ]; + security.wrappers.light.source = "${pkgs.light.out}/bin/light"; }; } diff --git a/nixos/modules/programs/shadow.nix b/nixos/modules/programs/shadow.nix index ce4d46e19bf..0f3f42901ba 100644 --- a/nixos/modules/programs/shadow.nix +++ b/nixos/modules/programs/shadow.nix @@ -101,11 +101,15 @@ in chpasswd = { rootOK = true; }; }; - security.setuidPrograms = [ "su" "chfn" ] - ++ [ "newuidmap" "newgidmap" ] # new in shadow 4.2.x - ++ lib.optionals config.users.mutableUsers - [ "passwd" "sg" "newgrp" ]; - + security.wrappers = { + su.source = "${pkgs.shadow.su}/bin/su"; + chfn.source = "${pkgs.shadow.out}/bin/chfn"; + newuidmap.source = "${pkgs.shadow.out}/bin/newuidmap"; + newgidmap.source = "${pkgs.shadow.out}/bin/newgidmap"; + } // (if config.users.mutableUsers then { + passwd.source = "${pkgs.shadow.out}/bin/passwd"; + sg.source = "${pkgs.shadow.out}/bin/sg"; + newgrp.source = "${pkgs.shadow.out}/bin/newgrp"; + } else {}); }; - } diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 5ae3f4bd6e6..e419474b3e3 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -10,7 +10,6 @@ with lib; (mkRenamedOptionModule [ "fonts" "enableFontConfig" ] [ "fonts" "fontconfig" "enable" ]) (mkRenamedOptionModule [ "fonts" "extraFonts" ] [ "fonts" "fonts" ]) - (mkRenamedOptionModule [ "security" "extraSetuidPrograms" ] [ "security" "setuidPrograms" ]) (mkRenamedOptionModule [ "networking" "enableWLAN" ] [ "networking" "wireless" "enable" ]) (mkRenamedOptionModule [ "networking" "enableRT73Firmware" ] [ "networking" "enableRalinkFirmware" ]) diff --git a/nixos/modules/security/apparmor-suid.nix b/nixos/modules/security/apparmor-suid.nix index 4a6d61d2676..dfbf5d859ba 100644 --- a/nixos/modules/security/apparmor-suid.nix +++ b/nixos/modules/security/apparmor-suid.nix @@ -19,7 +19,7 @@ with lib; config = mkIf (cfg.confineSUIDApplications) { security.apparmor.profiles = [ (pkgs.writeText "ping" '' #include - /var/setuid-wrappers/ping { + /run/wrappers/bin/ping { #include #include #include @@ -33,7 +33,6 @@ with lib; ${pkgs.attr.out}/lib/libattr.so* mr, ${pkgs.iputils}/bin/ping mixr, - /var/setuid-wrappers/ping.real r, #/etc/modules.conf r, diff --git a/nixos/modules/security/chromium-suid-sandbox.nix b/nixos/modules/security/chromium-suid-sandbox.nix index 88fbe518c2d..0458ffb6c46 100644 --- a/nixos/modules/security/chromium-suid-sandbox.nix +++ b/nixos/modules/security/chromium-suid-sandbox.nix @@ -27,6 +27,6 @@ in config = mkIf cfg.enable { environment.systemPackages = [ sandbox ]; - security.setuidPrograms = [ sandbox.passthru.sandboxExecutableName ]; + security.wrappers."${sandbox.passthru.sandboxExecutableName}".source = "${sandbox}/bin/${sandbox.passthru.sandboxExecutableName}"; }; } diff --git a/nixos/modules/security/duosec.nix b/nixos/modules/security/duosec.nix index 97e2d39dc07..9ca818e86ff 100644 --- a/nixos/modules/security/duosec.nix +++ b/nixos/modules/security/duosec.nix @@ -187,7 +187,8 @@ in ]; environment.systemPackages = [ pkgs.duo-unix ]; - security.setuidPrograms = [ "login_duo" ]; + + security.wrappers.login_duo.source = "${pkgs.duo-unix.out}/bin/login_duo"; environment.etc = loginCfgFile ++ pamCfgFile; /* If PAM *and* SSH are enabled, then don't do anything special. diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index 67652fbd1e7..e37c55aa1ac 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -472,19 +472,20 @@ in ++ optionals config.security.pam.enableU2F [ pkgs.pam_u2f ] ++ optionals config.security.pam.enableEcryptfs [ pkgs.ecryptfs ]; - security.setuidPrograms = - optionals config.security.pam.enableEcryptfs [ "mount.ecryptfs_private" "umount.ecryptfs_private" ]; + security.wrappers = { + unix_chkpwd = { + source = "${pkgs.pam}/sbin/unix_chkpwd.orig"; + owner = "root"; + setuid = true; + }; + } // (if config.security.pam.enableEcryptfs then { + "mount.ecryptfs_private".source = "${pkgs.ecryptfs.out}/bin/mount.ecryptfs_private"; + "umount.ecryptfs_private".source = "${pkgs.ecryptfs.out}/bin/umount.ecryptfs_private"; + } else {}); environment.etc = mapAttrsToList (n: v: makePAMService v) config.security.pam.services; - security.setuidOwners = [ { - program = "unix_chkpwd"; - source = "${pkgs.pam}/sbin/unix_chkpwd.orig"; - owner = "root"; - setuid = true; - } ]; - security.pam.services = { other.text = '' diff --git a/nixos/modules/security/pam_usb.nix b/nixos/modules/security/pam_usb.nix index 11708a1f016..6f811dab8d7 100644 --- a/nixos/modules/security/pam_usb.nix +++ b/nixos/modules/security/pam_usb.nix @@ -32,10 +32,12 @@ in config = mkIf (cfg.enable || anyUsbAuth) { - # pmount need to have a set-uid bit to make pam_usb works in user - # environment. (like su, sudo) + # Make sure pmount and pumount are setuid wrapped. + security.wrappers = { + pmount.source = "${pkgs.pmount.out}/bin/pmount"; + pumount.source = "${pkgs.pmount.out}/bin/pumount"; + }; - security.setuidPrograms = [ "pmount" "pumount" ]; environment.systemPackages = [ pkgs.pmount ]; }; diff --git a/nixos/modules/security/polkit.nix b/nixos/modules/security/polkit.nix index 507f81bbf07..419abb8b086 100644 --- a/nixos/modules/security/polkit.nix +++ b/nixos/modules/security/polkit.nix @@ -83,16 +83,10 @@ in security.pam.services.polkit-1 = {}; - security.setuidPrograms = [ "pkexec" ]; - - security.setuidOwners = [ - { program = "polkit-agent-helper-1"; - owner = "root"; - group = "root"; - setuid = true; - source = "${pkgs.polkit.out}/lib/polkit-1/polkit-agent-helper-1"; - } - ]; + security.wrappers = { + pkexec.source = "${pkgs.polkit.out}/bin/pkexec"; + "polkit-agent-helper-1".source = "${pkgs.polkit.out}/lib/polkit-1/polkit-agent-helper-1"; + }; system.activationScripts.polkit = '' diff --git a/nixos/modules/security/setuid-wrapper.c b/nixos/modules/security/setuid-wrapper.c deleted file mode 100644 index ffd0b65b762..00000000000 --- a/nixos/modules/security/setuid-wrapper.c +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Make sure assertions are not compiled out. */ -#undef NDEBUG - -extern char **environ; - -static char * wrapperDir = WRAPPER_DIR; - -int main(int argc, char * * argv) -{ - char self[PATH_MAX]; - - int len = readlink("/proc/self/exe", self, sizeof(self) - 1); - assert (len > 0); - self[len] = 0; - - /* Make sure that we are being executed from the right location, - i.e., `wrapperDir'. This is to prevent someone from - creating hard link `X' from some other location, along with a - false `X.real' file, to allow arbitrary programs from being - executed setuid. */ - assert ((strncmp(self, wrapperDir, strlen(wrapperDir)) == 0) && - (self[strlen(wrapperDir)] == '/')); - - /* Make *really* *really* sure that we were executed as `self', - and not, say, as some other setuid program. That is, our - effective uid/gid should match the uid/gid of `self'. */ - //printf("%d %d\n", geteuid(), getegid()); - - struct stat st; - assert (lstat(self, &st) != -1); - - //printf("%d %d\n", st.st_uid, st.st_gid); - - assert ((st.st_mode & S_ISUID) == 0 || - (st.st_uid == geteuid())); - - assert ((st.st_mode & S_ISGID) == 0 || - st.st_gid == getegid()); - - /* And, of course, we shouldn't be writable. */ - assert (!(st.st_mode & (S_IWGRP | S_IWOTH))); - - - /* Read the path of the real (wrapped) program from .real. */ - char realFN[PATH_MAX + 10]; - int realFNSize = snprintf (realFN, sizeof(realFN), "%s.real", self); - assert (realFNSize < sizeof(realFN)); - - int fdSelf = open(realFN, O_RDONLY); - assert (fdSelf != -1); - - char real[PATH_MAX]; - len = read(fdSelf, real, PATH_MAX); - assert (len != -1); - assert (len < sizeof (real)); - assert (len > 0); - real[len] = 0; - - close(fdSelf); - - //printf("real = %s, len = %d\n", real, len); - - execve(real, argv, environ); - - fprintf(stderr, "%s: cannot run `%s': %s\n", - argv[0], real, strerror(errno)); - - exit(1); -} diff --git a/nixos/modules/security/setuid-wrappers.nix b/nixos/modules/security/setuid-wrappers.nix deleted file mode 100644 index fe220c94313..00000000000 --- a/nixos/modules/security/setuid-wrappers.nix +++ /dev/null @@ -1,146 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - - inherit (config.security) wrapperDir; - - setuidWrapper = pkgs.stdenv.mkDerivation { - name = "setuid-wrapper"; - unpackPhase = "true"; - installPhase = '' - mkdir -p $out/bin - cp ${./setuid-wrapper.c} setuid-wrapper.c - gcc -Wall -O2 -DWRAPPER_DIR=\"/run/setuid-wrapper-dirs\" \ - setuid-wrapper.c -o $out/bin/setuid-wrapper - ''; - }; - -in - -{ - - ###### interface - - options = { - - security.setuidPrograms = mkOption { - type = types.listOf types.str; - default = []; - example = ["passwd"]; - description = '' - The Nix store cannot contain setuid/setgid programs directly. - For this reason, NixOS can automatically generate wrapper - programs that have the necessary privileges. This option - lists the names of programs in the system environment for - which setuid root wrappers should be created. - ''; - }; - - security.setuidOwners = mkOption { - type = types.listOf types.attrs; - default = []; - example = - [ { program = "sendmail"; - owner = "nobody"; - group = "postdrop"; - setuid = false; - setgid = true; - permissions = "u+rx,g+x,o+x"; - } - ]; - description = '' - This option allows the ownership and permissions on the setuid - wrappers for specific programs to be overridden from the - default (setuid root, but not setgid root). - ''; - }; - - security.wrapperDir = mkOption { - internal = true; - type = types.path; - default = "/var/setuid-wrappers"; - description = '' - This option defines the path to the setuid wrappers. It - should generally not be overriden. Some packages in Nixpkgs - expect that is - /var/setuid-wrappers. - ''; - }; - - }; - - - ###### implementation - - config = { - - security.setuidPrograms = [ "fusermount" ]; - - system.activationScripts.setuid = - let - setuidPrograms = - (map (x: { program = x; owner = "root"; group = "root"; setuid = true; }) - config.security.setuidPrograms) - ++ config.security.setuidOwners; - - makeSetuidWrapper = - { program - , source ? "" - , owner ? "nobody" - , group ? "nogroup" - , setuid ? false - , setgid ? false - , permissions ? "u+rx,g+x,o+x" - }: - - '' - if ! source=${if source != "" then source else "$(readlink -f $(PATH=$SETUID_PATH type -tP ${program}))"}; then - # If we can't find the program, fall back to the - # system profile. - source=/nix/var/nix/profiles/default/bin/${program} - fi - - cp ${setuidWrapper}/bin/setuid-wrapper $wrapperDir/${program} - echo -n "$source" > $wrapperDir/${program}.real - chmod 0000 $wrapperDir/${program} # to prevent races - chown ${owner}.${group} $wrapperDir/${program} - chmod "u${if setuid then "+" else "-"}s,g${if setgid then "+" else "-"}s,${permissions}" $wrapperDir/${program} - ''; - - in stringAfter [ "users" ] - '' - # Look in the system path and in the default profile for - # programs to be wrapped. - SETUID_PATH=${config.system.path}/bin:${config.system.path}/sbin - - mkdir -p /run/setuid-wrapper-dirs - wrapperDir=$(mktemp --directory --tmpdir=/run/setuid-wrapper-dirs setuid-wrappers.XXXXXXXXXX) - chmod a+rx $wrapperDir - - ${concatMapStrings makeSetuidWrapper setuidPrograms} - - if [ -L ${wrapperDir} ]; then - # Atomically replace the symlink - # See https://axialcorps.com/2013/07/03/atomically-replacing-files-and-directories/ - old=$(readlink ${wrapperDir}) - ln --symbolic --force --no-dereference $wrapperDir ${wrapperDir}-tmp - mv --no-target-directory ${wrapperDir}-tmp ${wrapperDir} - rm --force --recursive $old - elif [ -d ${wrapperDir} ]; then - # Compatibility with old state, just remove the folder and symlink - rm -f ${wrapperDir}/* - # if it happens to be a tmpfs - ${pkgs.utillinux}/bin/umount ${wrapperDir} || true - rm -d ${wrapperDir} - ln -d --symbolic $wrapperDir ${wrapperDir} - else - # For initial setup - ln --symbolic $wrapperDir ${wrapperDir} - fi - ''; - - }; - -} diff --git a/nixos/modules/security/sudo.nix b/nixos/modules/security/sudo.nix index f5612e1b0c5..67a9b9a45ee 100644 --- a/nixos/modules/security/sudo.nix +++ b/nixos/modules/security/sudo.nix @@ -81,7 +81,10 @@ in ${cfg.extraConfig} ''; - security.setuidPrograms = [ "sudo" "sudoedit" ]; + security.wrappers = { + sudo.source = "${pkgs.sudo.out}/bin/sudo"; + sudoedit.source = "${pkgs.sudo.out}/bin/sudoedit"; + }; environment.systemPackages = [ sudo ]; diff --git a/nixos/modules/security/wrappers/default.nix b/nixos/modules/security/wrappers/default.nix new file mode 100644 index 00000000000..c5b99c0c801 --- /dev/null +++ b/nixos/modules/security/wrappers/default.nix @@ -0,0 +1,216 @@ +{ config, lib, pkgs, ... }: +let + + inherit (config.security) wrapperDir wrappers setuidPrograms; + + programs = + (lib.mapAttrsToList + (n: v: (if v ? "program" then v else v // {program=n;})) + wrappers); + + securityWrapper = pkgs.stdenv.mkDerivation { + name = "security-wrapper"; + phases = [ "installPhase" "fixupPhase" ]; + buildInputs = [ pkgs.libcap pkgs.libcap_ng pkgs.linuxHeaders ]; + hardeningEnable = [ "pie" ]; + installPhase = '' + mkdir -p $out/bin + parentWrapperDir=$(dirname ${wrapperDir}) + gcc -Wall -O2 -DWRAPPER_DIR=\"$parentWrapperDir\" \ + -lcap-ng -lcap ${./wrapper.c} -o $out/bin/security-wrapper + ''; + }; + + ###### Activation script for the setcap wrappers + mkSetcapProgram = + { program + , capabilities + , source + , owner ? "nobody" + , group ? "nogroup" + , ... + }: + assert (lib.versionAtLeast (lib.getVersion config.boot.kernelPackages.kernel) "4.3"); + '' + cp ${securityWrapper}/bin/security-wrapper $wrapperDir/${program} + echo -n "${source}" > $wrapperDir/${program}.real + + # Prevent races + chmod 0000 $wrapperDir/${program} + chown ${owner}.${group} $wrapperDir/${program} + + # Set desired capabilities on the file plus cap_setpcap so + # the wrapper program can elevate the capabilities set on + # its file into the Ambient set. + ${pkgs.libcap.out}/bin/setcap "cap_setpcap,${capabilities}" $wrapperDir/${program} + + # Set the executable bit + chmod u+rx,g+x,o+x $wrapperDir/${program} + ''; + + ###### Activation script for the setuid wrappers + mkSetuidProgram = + { program + , source + , owner ? "nobody" + , group ? "nogroup" + , setuid ? false + , setgid ? false + , permissions ? "u+rx,g+x,o+x" + , ... + }: + '' + cp ${securityWrapper}/bin/security-wrapper $wrapperDir/${program} + echo -n "${source}" > $wrapperDir/${program}.real + + # Prevent races + chmod 0000 $wrapperDir/${program} + chown ${owner}.${group} $wrapperDir/${program} + + chmod "u${if setuid then "+" else "-"}s,g${if setgid then "+" else "-"}s,${permissions}" $wrapperDir/${program} + ''; + + mkWrappedPrograms = + builtins.map + (s: if (s ? "capabilities") + then mkSetcapProgram + ({ owner = "root"; + group = "root"; + } // s) + else if + (s ? "setuid" && s.setuid == true) || + (s ? "setguid" && s.setguid == true) || + (s ? "permissions") + then mkSetuidProgram s + else mkSetuidProgram + ({ owner = "root"; + group = "root"; + setuid = true; + setgid = false; + permissions = "u+rx,g+x,o+x"; + } // s) + ) programs; +in +{ + + ###### interface + + options = { + security.wrappers = lib.mkOption { + type = lib.types.attrs; + default = {}; + example = { + sendmail.source = "/nix/store/.../bin/sendmail"; + ping = { + source = "${pkgs.iputils.out}/bin/ping"; + owner = "nobody"; + group = "nogroup"; + capabilities = "cap_net_raw+ep"; + }; + }; + description = '' + This option allows the ownership and permissions on the + setuid wrappers for specific programs to be overridden from + the default (setuid root, but not setgid root). + + Additionally, this option can set capabilities on a + wrapper program that propagates those capabilities down to the + wrapped, real program. + + The program attribute is the name of + the program to be wrapped. If no source + attribute is provided, specifying the absolute path to the + program, then the program will be searched for in the path + environment variable. + + NOTE: cap_setpcap, which is required for the wrapper + program to be able to raise caps into the Ambient set is NOT + raised to the Ambient set so that the real program cannot + modify its own capabilities!! This may be too restrictive for + cases in which the real program needs cap_setpcap but it at + least leans on the side security paranoid vs. too + relaxed. + ''; + }; + + security.wrapperDir = lib.mkOption { + type = lib.types.path; + default = "/run/wrappers/bin"; + internal = true; + description = '' + This option defines the path to the wrapper programs. It + should not be overriden. + ''; + }; + }; + + ###### implementation + config = { + + security.wrappers.fusermount.source = "${pkgs.fuse}/bin/fusermount"; + + # Make sure our wrapperDir exports to the PATH env variable when + # initializing the shell + environment.extraInit = '' + # Wrappers override other bin directories. + export PATH="${wrapperDir}:$PATH" + ''; + + ###### setcap activation script + system.activationScripts.wrappers = + lib.stringAfter [ "users" ] + '' + # Look in the system path and in the default profile for + # programs to be wrapped. + WRAPPER_PATH=${config.system.path}/bin:${config.system.path}/sbin + + # Remove the old /var/setuid-wrappers path from the system... + # + # TODO: this is only necessary for ugprades 16.09 => 17.x; + # this conditional removal block needs to be removed after + # the release. + if [ -d /var/setuid-wrappers ]; then + rm -rf /var/setuid-wrappers + fi + + # Remove the old /run/setuid-wrappers-dir path from the + # system as well... + # + # TDOO: this is only necessary for ugprades 16.09 => 17.x; + # this conditional removal block needs to be removed after + # the release. + if [ -d /run/setuid-wrapper-dirs ]; then + rm -rf /run/setuid-wrapper-dirs + fi + + # Get the "/run/wrappers" path, we want to place the tmpdirs + # for the wrappers there + parentWrapperDir="$(dirname ${wrapperDir})" + + mkdir -p "$parentWrapperDir" + wrapperDir=$(mktemp --directory --tmpdir="$parentWrapperDir" wrappers.XXXXXXXXXX) + chmod a+rx $wrapperDir + + ${lib.concatStringsSep "\n" mkWrappedPrograms} + + if [ -L ${wrapperDir} ]; then + # Atomically replace the symlink + # See https://axialcorps.com/2013/07/03/atomically-replacing-files-and-directories/ + old=$(readlink -f ${wrapperDir}) + ln --symbolic --force --no-dereference $wrapperDir ${wrapperDir}-tmp + mv --no-target-directory ${wrapperDir}-tmp ${wrapperDir} + rm --force --recursive $old + elif [ -d ${wrapperDir} ]; then + # Compatibility with old state, just remove the folder and symlink + rm -f ${wrapperDir}/* + # if it happens to be a tmpfs + ${pkgs.utillinux}/bin/umount ${wrapperDir} || true + rm -d ${wrapperDir} + ln -d --symbolic $wrapperDir ${wrapperDir} + else + # For initial setup + ln --symbolic $wrapperDir ${wrapperDir} + fi + ''; + }; +} diff --git a/nixos/modules/security/wrappers/wrapper.c b/nixos/modules/security/wrappers/wrapper.c new file mode 100644 index 00000000000..7091e314bb2 --- /dev/null +++ b/nixos/modules/security/wrappers/wrapper.c @@ -0,0 +1,239 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Make sure assertions are not compiled out, we use them to codify +// invariants about this program and we want it to fail fast and +// loudly if they are violated. +#undef NDEBUG + +extern char **environ; + +// The WRAPPER_DIR macro is supplied at compile time so that it cannot +// be changed at runtime +static char * wrapperDir = WRAPPER_DIR; + +// Wrapper debug variable name +static char * wrapperDebug = "WRAPPER_DEBUG"; + +// Update the capabilities of the running process to include the given +// capability in the Ambient set. +static void set_ambient_cap(cap_value_t cap) +{ + capng_get_caps_process(); + + if (capng_update(CAPNG_ADD, CAPNG_INHERITABLE, (unsigned long) cap)) + { + perror("cannot raise the capability into the Inheritable set\n"); + exit(1); + } + + capng_apply(CAPNG_SELECT_CAPS); + + if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, (unsigned long) cap, 0, 0)) + { + perror("cannot raise the capability into the Ambient set\n"); + exit(1); + } +} + +// Given the path to this program, fetch its configured capability set +// (as set by `setcap ... /path/to/file`) and raise those capabilities +// into the Ambient set. +static int make_caps_ambient(const char *selfPath) +{ + cap_t caps = cap_get_file(selfPath); + + if(!caps) + { + if(getenv(wrapperDebug)) + fprintf(stderr, "no caps set or could not retrieve the caps for this file, not doing anything..."); + + return 1; + } + + // We use `cap_to_text` and iteration over the tokenized result + // string because, as of libcap's current release, there is no + // facility for retrieving an array of `cap_value_t`'s that can be + // given to `prctl` in order to lift that capability into the + // Ambient set. + // + // Some discussion was had around shot-gunning all of the + // capabilities we know about into the Ambient set but that has a + // security smell and I deemed the risk of the current + // implementation crashing the program to be lower than the risk + // of a privilege escalation security hole being introduced by + // raising all capabilities, even ones we didn't intend for the + // program, into the Ambient set. + // + // `cap_t` which is returned by `cap_get_*` is an opaque type and + // even if we could retrieve the bitmasks (which, as far as I can + // tell we cannot) in order to get the `cap_value_t` + // representation for each capability we would have to take the + // total number of capabilities supported and iterate over the + // sequence of integers up-to that maximum total, testing each one + // against the bitmask ((bitmask >> n) & 1) to see if it's set and + // aggregating each "capability integer n" that is set in the + // bitmask. + // + // That, combined with the fact that we can't easily get the + // bitmask anyway seemed much more brittle than fetching the + // `cap_t`, transforming it into a textual representation, + // tokenizing the string, and using `cap_from_name` on the token + // to get the `cap_value_t` that we need for `prctl`. There is + // indeed risk involved if the output string format of + // `cap_to_text` ever changes but at this time the combination of + // factors involving the below list have led me to the conclusion + // that the best implementation at this time is reading then + // parsing with *lots of documentation* about why we're doing it + // this way. + // + // 1. No explicit API for fetching an array of `cap_value_t`'s or + // for transforming a `cap_t` into such a representation + // 2. The risk of a crash is lower than lifting all capabilities + // into the Ambient set + // 3. libcap is depended on heavily in the Linux ecosystem so + // there is a high chance that the output representation of + // `cap_to_text` will not change which reduces our risk that + // this parsing step will cause a crash + // + // The preferred method, should it ever be available in the + // future, would be to use libcap API's to transform the result + // from a `cap_get_*` into an array of `cap_value_t`'s that can + // then be given to prctl. + // + // - Parnell + ssize_t capLen; + char* capstr = cap_to_text(caps, &capLen); + cap_free(caps); + + // TODO: For now, we assume that cap_to_text always starts its + // result string with " =" and that the first capability is listed + // immediately after that. We should verify this. + assert(capLen >= 2); + capstr += 2; + + char* saveptr = NULL; + for(char* tok = strtok_r(capstr, ",", &saveptr); tok; tok = strtok_r(NULL, ",", &saveptr)) + { + cap_value_t capnum; + if (cap_from_name(tok, &capnum)) + { + if(getenv(wrapperDebug)) + fprintf(stderr, "cap_from_name failed, skipping: %s", tok); + } + else if (capnum == CAP_SETPCAP) + { + // Check for the cap_setpcap capability, we set this on the + // wrapper so it can elevate the capabilities to the Ambient + // set but we do not want to propagate it down into the + // wrapped program. + // + // TODO: what happens if that's the behavior you want + // though???? I'm preferring a strict vs. loose policy here. + if(getenv(wrapperDebug)) + fprintf(stderr, "cap_setpcap in set, skipping it\n"); + } + else + { + set_ambient_cap(capnum); + + if(getenv(wrapperDebug)) + fprintf(stderr, "raised %s into the Ambient capability set\n", tok); + } + } + cap_free(capstr); + + return 0; +} + +int main(int argc, char * * argv) +{ + // I *think* it's safe to assume that a path from a symbolic link + // should safely fit within the PATH_MAX system limit. Though I'm + // not positive it's safe... + char selfPath[PATH_MAX]; + int selfPathSize = readlink("/proc/self/exe", selfPath, sizeof(selfPath)); + + assert(selfPathSize > 0); + + // Assert we have room for the zero byte, this ensures the path + // isn't being truncated because it's too big for the buffer. + // + // A better way to handle this might be to use something like the + // whereami library (https://github.com/gpakosz/whereami) or a + // loop that resizes the buffer and re-reads the link if the + // contents are being truncated. + assert(selfPathSize < sizeof(selfPath)); + + // Set the zero byte since readlink doesn't do that for us. + selfPath[selfPathSize] = '\0'; + + // Make sure that we are being executed from the right location, + // i.e., `safeWrapperDir'. This is to prevent someone from creating + // hard link `X' from some other location, along with a false + // `X.real' file, to allow arbitrary programs from being executed + // with elevated capabilities. + int len = strlen(wrapperDir); + if (len > 0 && '/' == wrapperDir[len - 1]) + --len; + assert(!strncmp(selfPath, wrapperDir, len)); + assert('/' == wrapperDir[0]); + assert('/' == selfPath[len]); + + // Make *really* *really* sure that we were executed as + // `selfPath', and not, say, as some other setuid program. That + // is, our effective uid/gid should match the uid/gid of + // `selfPath'. + struct stat st; + assert(lstat(selfPath, &st) != -1); + + assert(!(st.st_mode & S_ISUID) || (st.st_uid == geteuid())); + assert(!(st.st_mode & S_ISGID) || (st.st_gid == getegid())); + + // And, of course, we shouldn't be writable. + assert(!(st.st_mode & (S_IWGRP | S_IWOTH))); + + // Read the path of the real (wrapped) program from .real. + char realFN[PATH_MAX + 10]; + int realFNSize = snprintf (realFN, sizeof(realFN), "%s.real", selfPath); + assert (realFNSize < sizeof(realFN)); + + int fdSelf = open(realFN, O_RDONLY); + assert (fdSelf != -1); + + char sourceProg[PATH_MAX]; + len = read(fdSelf, sourceProg, PATH_MAX); + assert (len != -1); + assert (len < sizeof(sourceProg)); + assert (len > 0); + sourceProg[len] = 0; + + close(fdSelf); + + // Read the capabilities set on the wrapper and raise them in to + // the Ambient set so the program we're wrapping receives the + // capabilities too! + make_caps_ambient(selfPath); + + execve(sourceProg, argv, environ); + + fprintf(stderr, "%s: cannot run `%s': %s\n", + argv[0], sourceProg, strerror(errno)); + + exit(1); +} + + diff --git a/nixos/modules/services/logging/logcheck.nix b/nixos/modules/services/logging/logcheck.nix index 27ed5374f56..72925b95cae 100644 --- a/nixos/modules/services/logging/logcheck.nix +++ b/nixos/modules/services/logging/logcheck.nix @@ -29,8 +29,8 @@ let }; cronJob = '' - @reboot logcheck env PATH=/var/setuid-wrappers:$PATH nice -n10 ${pkgs.logcheck}/sbin/logcheck -R ${flags} - 2 ${cfg.timeOfDay} * * * logcheck env PATH=/var/setuid-wrappers:$PATH nice -n10 ${pkgs.logcheck}/sbin/logcheck ${flags} + @reboot logcheck env PATH=/run/wrappers/bin:$PATH nice -n10 ${pkgs.logcheck}/sbin/logcheck -R ${flags} + 2 ${cfg.timeOfDay} * * * logcheck env PATH=/run/wrappers/bin:$PATH nice -n10 ${pkgs.logcheck}/sbin/logcheck ${flags} ''; writeIgnoreRule = name: {level, regex, ...}: diff --git a/nixos/modules/services/mail/dovecot.nix b/nixos/modules/services/mail/dovecot.nix index f2097638c63..3b25e41edb1 100644 --- a/nixos/modules/services/mail/dovecot.nix +++ b/nixos/modules/services/mail/dovecot.nix @@ -13,7 +13,7 @@ let '' base_dir = ${baseDir} protocols = ${concatStringsSep " " cfg.protocols} - sendmail_path = /var/setuid-wrappers/sendmail + sendmail_path = /run/wrappers/bin/sendmail '' (if isNull cfg.sslServerCert then '' diff --git a/nixos/modules/services/mail/exim.nix b/nixos/modules/services/mail/exim.nix index e0890d96a88..440eae281f4 100644 --- a/nixos/modules/services/mail/exim.nix +++ b/nixos/modules/services/mail/exim.nix @@ -70,7 +70,7 @@ in etc."exim.conf".text = '' exim_user = ${cfg.user} exim_group = ${cfg.group} - exim_path = /var/setuid-wrappers/exim + exim_path = /run/wrappers/bin/exim spool_directory = ${cfg.spoolDir} ${cfg.config} ''; @@ -89,7 +89,7 @@ in gid = config.ids.gids.exim; }; - security.setuidPrograms = [ "exim" ]; + security.wrappers.exim.source = "${exim}/bin/exim"; systemd.services.exim = { description = "Exim Mail Daemon"; diff --git a/nixos/modules/services/mail/mail.nix b/nixos/modules/services/mail/mail.nix index 63e8d78b5b0..cfe1b5496a4 100644 --- a/nixos/modules/services/mail/mail.nix +++ b/nixos/modules/services/mail/mail.nix @@ -26,7 +26,7 @@ with lib; config = mkIf (config.services.mail.sendmailSetuidWrapper != null) { - security.setuidOwners = [ config.services.mail.sendmailSetuidWrapper ]; + security.wrappers.sendmail = config.services.mail.sendmailSetuidWrapper; }; diff --git a/nixos/modules/services/monitoring/munin.nix b/nixos/modules/services/monitoring/munin.nix index 57df16b58d9..6d2ce538368 100644 --- a/nixos/modules/services/monitoring/munin.nix +++ b/nixos/modules/services/monitoring/munin.nix @@ -34,7 +34,7 @@ let cap=$(sed -nr 's/.*#%#\s+capabilities\s*=\s*(.+)/\1/p' $file) wrapProgram $file \ - --set PATH "/var/setuid-wrappers:/run/current-system/sw/bin:/run/current-system/sw/bin" \ + --set PATH "/run/wrappers/bin:/run/current-system/sw/bin:/run/current-system/sw/bin" \ --set MUNIN_LIBDIR "${pkgs.munin}/lib" \ --set MUNIN_PLUGSTATE "/var/run/munin" @@ -183,7 +183,7 @@ in mkdir -p /etc/munin/plugins rm -rf /etc/munin/plugins/* - PATH="/var/setuid-wrappers:/run/current-system/sw/bin:/run/current-system/sw/bin" ${pkgs.munin}/sbin/munin-node-configure --shell --families contrib,auto,manual --config ${nodeConf} --libdir=${muninPlugins} --servicedir=/etc/munin/plugins 2>/dev/null | ${pkgs.bash}/bin/bash + PATH="/run/wrappers/bin:/run/current-system/sw/bin:/run/current-system/sw/bin" ${pkgs.munin}/sbin/munin-node-configure --shell --families contrib,auto,manual --config ${nodeConf} --libdir=${muninPlugins} --servicedir=/etc/munin/plugins 2>/dev/null | ${pkgs.bash}/bin/bash ''; serviceConfig = { ExecStart = "${pkgs.munin}/sbin/munin-node --config ${nodeConf} --servicedir /etc/munin/plugins/"; diff --git a/nixos/modules/services/monitoring/smartd.nix b/nixos/modules/services/monitoring/smartd.nix index f2834f288f9..4d10299a987 100644 --- a/nixos/modules/services/monitoring/smartd.nix +++ b/nixos/modules/services/monitoring/smartd.nix @@ -124,7 +124,7 @@ in }; mailer = mkOption { - default = "/var/setuid-wrappers/sendmail"; + default = "/run/wrappers/bin/sendmail"; type = types.path; description = '' Sendmail-compatible binary to be used to send the messages. diff --git a/nixos/modules/services/network-filesystems/samba.nix b/nixos/modules/services/network-filesystems/samba.nix index 7de85b59e2a..09a11585bc9 100644 --- a/nixos/modules/services/network-filesystems/samba.nix +++ b/nixos/modules/services/network-filesystems/samba.nix @@ -30,7 +30,7 @@ let '' [ global ] security = ${cfg.securityType} - passwd program = /var/setuid-wrappers/passwd %u + passwd program = /run/wrappers/bin/passwd %u pam password change = ${smbToString cfg.syncPasswordsByPam} invalid users = ${smbToString cfg.invalidUsers} diff --git a/nixos/modules/services/networking/gale.nix b/nixos/modules/services/networking/gale.nix index bc975159cdf..fd83f9e3c1b 100644 --- a/nixos/modules/services/networking/gale.nix +++ b/nixos/modules/services/networking/gale.nix @@ -141,7 +141,7 @@ in setgid = false; }; - security.setuidOwners = [ cfg.setuidWrapper ]; + security.wrappers.gksign = cfg.setuidWrapper; systemd.services.gale-galed = { description = "Gale messaging daemon"; diff --git a/nixos/modules/services/networking/prayer.nix b/nixos/modules/services/networking/prayer.nix index 9d63f549b23..8cd4a082353 100644 --- a/nixos/modules/services/networking/prayer.nix +++ b/nixos/modules/services/networking/prayer.nix @@ -18,7 +18,7 @@ let var_prefix = "${stateDir}" prayer_user = "${prayerUser}" prayer_group = "${prayerGroup}" - sendmail_path = "/var/setuid-wrappers/sendmail" + sendmail_path = "/run/wrappers/bin/sendmail" use_http_port ${cfg.port} diff --git a/nixos/modules/services/networking/smokeping.nix b/nixos/modules/services/networking/smokeping.nix index 6648ada0c0d..bac79474527 100644 --- a/nixos/modules/services/networking/smokeping.nix +++ b/nixos/modules/services/networking/smokeping.nix @@ -226,7 +226,7 @@ in sendmail = mkOption { type = types.nullOr types.path; default = null; - example = "/var/setuid-wrappers/sendmail"; + example = "/run/wrappers/bin/sendmail"; description = "Use this sendmail compatible script to deliver alerts"; }; smokeMailTemplate = mkOption { @@ -273,7 +273,10 @@ in message = "services.smokeping: sendmail and Mailhost cannot both be enabled."; } ]; - security.setuidPrograms = [ "fping" "fping6" ]; + security.wrappers = { + fping.source = "${pkgs.fping}/bin/fping"; + "fping6".source = "${pkgs.fping}/bin/fping6"; + }; environment.systemPackages = [ pkgs.fping ]; users.extraUsers = singleton { name = cfg.user; diff --git a/nixos/modules/services/scheduling/atd.nix b/nixos/modules/services/scheduling/atd.nix index 2070b2ffa01..f3ada6b7496 100644 --- a/nixos/modules/services/scheduling/atd.nix +++ b/nixos/modules/services/scheduling/atd.nix @@ -42,13 +42,13 @@ in config = mkIf cfg.enable { - security.setuidOwners = map (program: { - inherit program; + security.wrappers = map (program: {"${program}" = { + source = "${pkgs.atd}/bin/${program}"; owner = "atd"; group = "atd"; setuid = true; setgid = true; - }) [ "at" "atq" "atrm" "batch" ]; + };}) [ "at" "atq" "atrm" "batch" ]; environment.systemPackages = [ at ]; diff --git a/nixos/modules/services/scheduling/cron.nix b/nixos/modules/services/scheduling/cron.nix index f5e132fd77d..cc6eb96bf5d 100644 --- a/nixos/modules/services/scheduling/cron.nix +++ b/nixos/modules/services/scheduling/cron.nix @@ -20,7 +20,7 @@ let cronNixosPkg = pkgs.cron.override { # The mail.nix nixos module, if there is any local mail system enabled, # should have sendmail in this path. - sendmailPath = "/var/setuid-wrappers/sendmail"; + sendmailPath = "/run/wrappers/bin/sendmail"; }; allFiles = @@ -61,7 +61,7 @@ in A list of Cron jobs to be appended to the system-wide crontab. See the manual page for crontab for the expected format. If you want to get the results mailed you must setuid - sendmail. See + sendmail. See If neither /var/cron/cron.deny nor /var/cron/cron.allow exist only root will is allowed to have its own crontab file. The /var/cron/cron.deny file @@ -92,13 +92,9 @@ in config = mkMerge [ { services.cron.enable = mkDefault (allFiles != []); } - (mkIf (config.services.cron.enable) { - - security.setuidPrograms = [ "crontab" ]; - + security.wrappers.crontab.source = "${pkgs.cronNixosPkg.out}/bin/crontab"; environment.systemPackages = [ cronNixosPkg ]; - environment.etc.crontab = { source = pkgs.runCommand "crontabs" { inherit allFiles; preferLocalBuild = true; } '' diff --git a/nixos/modules/services/scheduling/fcron.nix b/nixos/modules/services/scheduling/fcron.nix index 7b4665a8204..e4ada276871 100644 --- a/nixos/modules/services/scheduling/fcron.nix +++ b/nixos/modules/services/scheduling/fcron.nix @@ -96,7 +96,7 @@ in fcronallow = /etc/fcron.allow fcrondeny = /etc/fcron.deny shell = /bin/sh - sendmail = /var/setuid-wrappers/sendmail + sendmail = /run/wrappers/bin/sendmail editor = /run/current-system/sw/bin/vi ''; target = "fcron.conf"; @@ -106,8 +106,7 @@ in environment.systemPackages = [ pkgs.fcron ]; - security.setuidPrograms = [ "fcrontab" ]; - + security.wrappers.fcrontab.source = "${pkgs.fcron.out}/bin/fcrontab"; systemd.services.fcron = { description = "fcron daemon"; after = [ "local-fs.target" ]; diff --git a/nixos/modules/services/system/dbus.nix b/nixos/modules/services/system/dbus.nix index aeb5bf9c7a3..33bc890a78c 100644 --- a/nixos/modules/services/system/dbus.nix +++ b/nixos/modules/services/system/dbus.nix @@ -104,15 +104,14 @@ in systemd.packages = [ pkgs.dbus.daemon ]; - security.setuidOwners = singleton - { program = "dbus-daemon-launch-helper"; - source = "${pkgs.dbus.daemon}/libexec/dbus-daemon-launch-helper"; - owner = "root"; - group = "messagebus"; - setuid = true; - setgid = false; - permissions = "u+rx,g+rx,o-rx"; - }; + security.wrappers.dbus-daemon-launch-helper = { + source = "${pkgs.dbus.daemon}/libexec/dbus-daemon-launch-helper"; + owner = "root"; + group = "messagebus"; + setuid = true; + setgid = false; + permissions = "u+rx,g+rx,o-rx"; + }; services.dbus.packages = [ pkgs.dbus.out diff --git a/nixos/modules/services/x11/desktop-managers/enlightenment.nix b/nixos/modules/services/x11/desktop-managers/enlightenment.nix index 7ea8b30d23d..d908553ccdf 100644 --- a/nixos/modules/services/x11/desktop-managers/enlightenment.nix +++ b/nixos/modules/services/x11/desktop-managers/enlightenment.nix @@ -62,7 +62,7 @@ in ''; }]; - security.setuidPrograms = [ "e_freqset" ]; + security.wrappers.e_freqset.source = "${e.enlightenment.out}/bin/e_freqset"; environment.etc = singleton { source = "${pkgs.xkeyboard_config}/etc/X11/xkb"; diff --git a/nixos/modules/services/x11/desktop-managers/kde5.nix b/nixos/modules/services/x11/desktop-managers/kde5.nix index 644fd8d7752..06f9f0a62ef 100644 --- a/nixos/modules/services/x11/desktop-managers/kde5.nix +++ b/nixos/modules/services/x11/desktop-managers/kde5.nix @@ -61,24 +61,13 @@ in ''} exec "${kde5.startkde}" - ''; }; - security.setuidOwners = [ - { - program = "kcheckpass"; - source = "${kde5.plasma-workspace.out}/lib/libexec/kcheckpass"; - owner = "root"; - setuid = true; - } - { - program = "start_kdeinit"; - source = "${kde5.kinit.out}/lib/libexec/kf5/start_kdeinit"; - owner = "root"; - setuid = true; - } - ]; + security.wrappers = { + kcheckpass.source = "${kde5.plasma-workspace.out}/lib/libexec/kcheckpass"; + "start_kdeinit".source = "${kde5.kinit.out}/lib/libexec/kf5/start_kdeinit"; + }; environment.systemPackages = [ diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix index d8ebe0af088..28c7b358093 100644 --- a/nixos/modules/tasks/network-interfaces.nix +++ b/nixos/modules/tasks/network-interfaces.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, utils, ... }: +{ config, lib, pkgs, utils, stdenv, ... }: with lib; with utils; @@ -933,7 +933,22 @@ in (i: flip map [ "4" "6" ] (v: nameValuePair "net.ipv${v}.conf.${i.name}.proxy_arp" true)) )); - security.setuidPrograms = [ "ping" "ping6" ]; + # Capabilities won't work unless we have at-least a 4.3 Linux + # kernel because we need the ambient capability + security.wrappers = if (versionAtLeast (getVersion config.boot.kernelPackages.kernel) "4.3") then { + ping = { + source = "${pkgs.iputils.out}/bin/ping"; + capabilities = "cap_net_raw+p"; + }; + + ping6 = { + source = "${pkgs.iputils.out}/bin/ping6"; + capabilities = "cap_net_raw+p"; + }; + } else { + ping.source = "${pkgs.iputils.out}/bin/ping"; + "ping6".source = "${pkgs.iputils.out}/bin/ping6"; + }; # Set the host and domain names in the activation script. Don't # clear it if it's not configured in the NixOS configuration, diff --git a/nixos/modules/virtualisation/virtualbox-host.nix b/nixos/modules/virtualisation/virtualbox-host.nix index 7214543871d..501ed9bc683 100644 --- a/nixos/modules/virtualisation/virtualbox-host.nix +++ b/nixos/modules/virtualisation/virtualbox-host.nix @@ -68,14 +68,13 @@ in boot.extraModulePackages = [ kernelModules ]; environment.systemPackages = [ virtualbox ]; - security.setuidOwners = let - mkSuid = program: { - inherit program; + security.wrappers = let + mkSuid = program: {"${program}" = { source = "${virtualbox}/libexec/virtualbox/${program}"; owner = "root"; group = "vboxusers"; setuid = true; - }; + };}; in mkIf cfg.enableHardening (map mkSuid [ "VBoxHeadless" "VBoxNetAdpCtl" @@ -99,7 +98,7 @@ in SUBSYSTEM=="usb", ACTION=="remove", ENV{DEVTYPE}=="usb_device", RUN+="${virtualbox}/libexec/virtualbox/VBoxCreateUSBNode.sh --remove $major $minor" ''; - # Since we lack the right setuid binaries, set up a host-only network by default. + # Since we lack the right setuid/setcap binaries, set up a host-only network by default. } (mkIf cfg.addNetworkInterface { systemd.services."vboxnet0" = { description = "VirtualBox vboxnet0 Interface"; diff --git a/nixos/tests/smokeping.nix b/nixos/tests/smokeping.nix index 9de3030417f..4c77e4b7861 100644 --- a/nixos/tests/smokeping.nix +++ b/nixos/tests/smokeping.nix @@ -14,7 +14,7 @@ import ./make-test.nix ({ pkgs, ...} : { mailHost = "127.0.0.2"; probeConfig = '' + FPing - binary = /var/setuid-wrappers/fping + binary = /run/wrappers/bin/fping offset = 0% ''; }; diff --git a/pkgs/applications/editors/sublime3/default.nix b/pkgs/applications/editors/sublime3/default.nix index c7badf6a77c..f900a4e9147 100644 --- a/pkgs/applications/editors/sublime3/default.nix +++ b/pkgs/applications/editors/sublime3/default.nix @@ -1,5 +1,5 @@ { fetchurl, stdenv, glib, xorg, cairo, gtk2, pango, makeWrapper, openssl, bzip2, - pkexecPath ? "/var/setuid-wrappers/pkexec", libredirect, + pkexecPath ? "/run/wrappers/bin/pkexec", libredirect, gksuSupport ? false, gksu}: assert stdenv.system == "i686-linux" || stdenv.system == "x86_64-linux"; diff --git a/pkgs/applications/networking/browsers/chromium/default.nix b/pkgs/applications/networking/browsers/chromium/default.nix index d014999a667..c59d6b00945 100644 --- a/pkgs/applications/networking/browsers/chromium/default.nix +++ b/pkgs/applications/networking/browsers/chromium/default.nix @@ -83,9 +83,9 @@ in stdenv.mkDerivation { ed -v -s "$out/bin/chromium" << EOF 2i - if [ -x "/var/setuid-wrappers/${sandboxExecutableName}" ] + if [ -x "/run/wrappers/bin/${sandboxExecutableName}" ] then - export CHROME_DEVEL_SANDBOX="/var/setuid-wrappers/${sandboxExecutableName}" + export CHROME_DEVEL_SANDBOX="/run/wrappers/bin/${sandboxExecutableName}" else export CHROME_DEVEL_SANDBOX="$sandbox/bin/${sandboxExecutableName}" fi diff --git a/pkgs/applications/networking/instant-messengers/gale/gale-install.in.patch b/pkgs/applications/networking/instant-messengers/gale/gale-install.in.patch index f9c3e3c5592..33e3e09a96d 100644 --- a/pkgs/applications/networking/instant-messengers/gale/gale-install.in.patch +++ b/pkgs/applications/networking/instant-messengers/gale/gale-install.in.patch @@ -26,7 +26,7 @@ index 50e8ad8..eec0ed2 100644 + is_nixos=no +fi + -+if [ -u /var/setuid-wrappers/gksign ]; then ++if [ -u /run/wrappers/bin/gksign ]; then + cat </dev/null") == 0) { diff --git a/pkgs/applications/version-management/gitlab/remove-hardcoded-locations.patch b/pkgs/applications/version-management/gitlab/remove-hardcoded-locations.patch index dec0f752fb7..dfd024a762a 100644 --- a/pkgs/applications/version-management/gitlab/remove-hardcoded-locations.patch +++ b/pkgs/applications/version-management/gitlab/remove-hardcoded-locations.patch @@ -11,7 +11,7 @@ index a9d8ac4..85f13f5 100644 - # # arguments: '-i -t' - # # } + config.action_mailer.sendmail_settings = { -+ location: '/var/setuid-wrappers/sendmail', ++ location: '/run/wrappers/bin/sendmail', + arguments: '-i -t' + } config.action_mailer.perform_deliveries = true diff --git a/pkgs/applications/virtualization/virtualbox/hardened.patch b/pkgs/applications/virtualization/virtualbox/hardened.patch index 37d2ad3a515..8d408d3494e 100644 --- a/pkgs/applications/virtualization/virtualbox/hardened.patch +++ b/pkgs/applications/virtualization/virtualbox/hardened.patch @@ -96,7 +96,7 @@ index 95dc9a7..39170bc 100644 /* get the path to the executable */ char szPath[RTPATH_MAX]; - RTPathAppPrivateArch(szPath, sizeof(szPath) - 1); -+ RTStrCopy(szPath, sizeof(szPath) - 1, "/var/setuid-wrappers"); ++ RTStrCopy(szPath, sizeof(szPath) - 1, "/run/wrappers/bin"); size_t cchBufLeft = strlen(szPath); szPath[cchBufLeft++] = RTPATH_DELIMITER; szPath[cchBufLeft] = 0; @@ -154,7 +154,7 @@ index be2ad8f..7ddf105 100644 +RTDECL(int) RTPathSuidDir(char *pszPath, size_t cchPath) +{ -+ return RTStrCopy(pszPath, cchPath, "/var/setuid-wrappers"); ++ return RTStrCopy(pszPath, cchPath, "/run/wrappers/bin"); +} + + @@ -174,7 +174,7 @@ index 7bde6af..2656cae 100644 + * will cut off everything after the rightmost / as this function is analogous + * to RTProcGetExecutablePath(). + */ -+#define SUIDDIR "/var/setuid-wrappers/" ++#define SUIDDIR "/run/wrappers/bin/" + +RTR3DECL(char *) RTProcGetSuidPath(char *pszExecPath, size_t cbExecPath) +{ diff --git a/pkgs/build-support/build-fhs-userenv/env.nix b/pkgs/build-support/build-fhs-userenv/env.nix index 8bc34d672c9..9a1897695a9 100644 --- a/pkgs/build-support/build-fhs-userenv/env.nix +++ b/pkgs/build-support/build-fhs-userenv/env.nix @@ -51,7 +51,7 @@ let export PS1='${name}-chrootenv:\u@\h:\w\$ ' export LOCALE_ARCHIVE='/usr/lib/locale/locale-archive' export LD_LIBRARY_PATH='/run/opengl-driver/lib:/run/opengl-driver-32/lib:/usr/lib:/usr/lib32' - export PATH='/var/setuid-wrappers:/usr/bin:/usr/sbin' + export PATH='/run/wrappers/bin:/usr/bin:/usr/sbin' export PKG_CONFIG_PATH=/usr/lib/pkgconfig # Force compilers to look in default search paths diff --git a/pkgs/desktops/enlightenment/enlightenment.nix b/pkgs/desktops/enlightenment/enlightenment.nix index b16b10952a2..3949bffaba1 100644 --- a/pkgs/desktops/enlightenment/enlightenment.nix +++ b/pkgs/desktops/enlightenment/enlightenment.nix @@ -42,13 +42,13 @@ stdenv.mkDerivation rec { # this is a hack and without this cpufreq module is not working. does the following: # 1. moves the "freqset" binary to "e_freqset", # 2. linkes "e_freqset" to enlightenment/bin so that, - # 3. setuidPrograms detects it and makes appropriate stuff to /var/setuid-wrappers/e_freqset, - # 4. and finaly, linkes /var/setuid-wrappers/e_freqset to original destination where enlightenment wants it + # 3. wrappers.setuid detects it and places wrappers in /run/wrappers/bin/e_freqset, + # 4. and finally, links /run/wrappers/bin/e_freqset to original destination where enlightenment wants it postInstall = '' export CPUFREQ_DIRPATH=`readlink -f $out/lib/enlightenment/modules/cpufreq/linux-gnu-*`; mv $CPUFREQ_DIRPATH/freqset $CPUFREQ_DIRPATH/e_freqset ln -sv $CPUFREQ_DIRPATH/e_freqset $out/bin/e_freqset - ln -sv /var/setuid-wrappers/e_freqset $CPUFREQ_DIRPATH/freqset + ln -sv /run/wrappers/bin/e_freqset $CPUFREQ_DIRPATH/freqset ''; meta = with stdenv.lib; { diff --git a/pkgs/development/libraries/kde-frameworks/kinit/start_kdeinit-path.patch b/pkgs/development/libraries/kde-frameworks/kinit/start_kdeinit-path.patch index fbecf9433f6..e3bfc2ebe6b 100644 --- a/pkgs/development/libraries/kde-frameworks/kinit/start_kdeinit-path.patch +++ b/pkgs/development/libraries/kde-frameworks/kinit/start_kdeinit-path.patch @@ -7,7 +7,7 @@ Index: kinit-5.24.0/src/start_kdeinit/start_kdeinit_wrapper.c #include -#define EXECUTE CMAKE_INSTALL_FULL_LIBEXECDIR_KF5 "/start_kdeinit" -+#define EXECUTE "/var/setuid-wrappers/start_kdeinit" ++#define EXECUTE "/run/wrappers/bin/start_kdeinit" #if KDEINIT_OOM_PROTECT diff --git a/pkgs/development/libraries/libgksu/default.nix b/pkgs/development/libraries/libgksu/default.nix index 0de84b1141d..e96ef7329a2 100644 --- a/pkgs/development/libraries/libgksu/default.nix +++ b/pkgs/development/libraries/libgksu/default.nix @@ -57,8 +57,8 @@ stdenv.mkDerivation rec { # Fix some binary paths sed -i -e 's|/usr/bin/xauth|${xauth}/bin/xauth|g' libgksu/gksu-run-helper.c libgksu/libgksu.c - sed -i -e 's|/usr/bin/sudo|/var/setuid-wrappers/sudo|g' libgksu/libgksu.c - sed -i -e 's|/bin/su\([^d]\)|/var/setuid-wrappers/su\1|g' libgksu/libgksu.c + sed -i -e 's|/usr/bin/sudo|/run/wrappers/bin/sudo|g' libgksu/libgksu.c + sed -i -e 's|/bin/su\([^d]\)|/run/wrappers/bin/su\1|g' libgksu/libgksu.c touch NEWS README ''; diff --git a/pkgs/development/libraries/polkit/default.nix b/pkgs/development/libraries/polkit/default.nix index ff67ff8a1bb..27482743d2c 100644 --- a/pkgs/development/libraries/polkit/default.nix +++ b/pkgs/development/libraries/polkit/default.nix @@ -5,7 +5,7 @@ let system = "/var/run/current-system/sw"; - setuid = "/var/setuid-wrappers"; #TODO: from config.security.wrapperDir; + setuid = "/run/wrappers/bin"; #TODO: from config.security.wrapperDir; foolVars = { SYSCONF = "/etc"; diff --git a/pkgs/development/tools/unity3d/default.nix b/pkgs/development/tools/unity3d/default.nix index b2c96beeeb3..73cb902ae69 100644 --- a/pkgs/development/tools/unity3d/default.nix +++ b/pkgs/development/tools/unity3d/default.nix @@ -94,7 +94,7 @@ in stdenv.mkDerivation rec { unitydir="$out/opt/Unity/Editor" mkdir -p $unitydir mv Editor/* $unitydir - ln -sf /var/setuid-wrappers/${chromium.sandboxExecutableName} $unitydir/chrome-sandbox + ln -sf /run/wrappers/bin/${chromium.sandboxExecutableName} $unitydir/chrome-sandbox mkdir -p $out/share/applications sed "/^Exec=/c\Exec=$out/bin/unity-editor" \ diff --git a/pkgs/os-specific/linux/fuse/default.nix b/pkgs/os-specific/linux/fuse/default.nix index 3024c488a13..b36d13a0b1d 100644 --- a/pkgs/os-specific/linux/fuse/default.nix +++ b/pkgs/os-specific/linux/fuse/default.nix @@ -28,7 +28,7 @@ stdenv.mkDerivation rec { # Ensure that FUSE calls the setuid wrapper, not # $out/bin/fusermount. It falls back to calling fusermount in # $PATH, so it should also work on non-NixOS systems. - export NIX_CFLAGS_COMPILE="-DFUSERMOUNT_DIR=\"/var/setuid-wrappers\"" + export NIX_CFLAGS_COMPILE="-DFUSERMOUNT_DIR=\"/run/wrappers/bin\"" sed -e 's@/bin/@${utillinux}/bin/@g' -i lib/mount_util.c sed -e 's@CONFIG_RPATH=/usr/share/gettext/config.rpath@CONFIG_RPATH=${gettext}/share/gettext/config.rpath@' -i makeconf.sh diff --git a/pkgs/os-specific/linux/mdadm/4.nix b/pkgs/os-specific/linux/mdadm/4.nix index d929668a26a..05d98de0b23 100644 --- a/pkgs/os-specific/linux/mdadm/4.nix +++ b/pkgs/os-specific/linux/mdadm/4.nix @@ -31,7 +31,7 @@ stdenv.mkDerivation rec { preConfigure = '' sed -e 's@/lib/udev@''${out}/lib/udev@' \ -e 's@ -Werror @ @' \ - -e 's@/usr/sbin/sendmail@/var/setuid-wrappers/sendmail@' -i Makefile + -e 's@/usr/sbin/sendmail@/run/wrappers/bin/sendmail@' -i Makefile ''; meta = { diff --git a/pkgs/os-specific/linux/mdadm/default.nix b/pkgs/os-specific/linux/mdadm/default.nix index 3fa7e2ba8d1..e0109791ef2 100644 --- a/pkgs/os-specific/linux/mdadm/default.nix +++ b/pkgs/os-specific/linux/mdadm/default.nix @@ -31,7 +31,7 @@ stdenv.mkDerivation rec { preConfigure = '' sed -e 's@/lib/udev@''${out}/lib/udev@' \ -e 's@ -Werror @ @' \ - -e 's@/usr/sbin/sendmail@/var/setuid-wrappers/sendmail@' -i Makefile + -e 's@/usr/sbin/sendmail@/run/wrappers/bin/sendmail@' -i Makefile ''; meta = { diff --git a/pkgs/os-specific/linux/pam/default.nix b/pkgs/os-specific/linux/pam/default.nix index d84c6224eeb..5189b84ff7e 100644 --- a/pkgs/os-specific/linux/pam/default.nix +++ b/pkgs/os-specific/linux/pam/default.nix @@ -34,7 +34,7 @@ stdenv.mkDerivation rec { postInstall = '' mv -v $out/sbin/unix_chkpwd{,.orig} - ln -sv /var/setuid-wrappers/unix_chkpwd $out/sbin/unix_chkpwd + ln -sv /run/wrappers/bin/unix_chkpwd $out/sbin/unix_chkpwd ''; /* rm -rf $out/etc mkdir -p $modules/lib diff --git a/pkgs/os-specific/linux/util-linux/default.nix b/pkgs/os-specific/linux/util-linux/default.nix index f7f60e8997f..6c3aacbef29 100644 --- a/pkgs/os-specific/linux/util-linux/default.nix +++ b/pkgs/os-specific/linux/util-linux/default.nix @@ -36,7 +36,7 @@ stdenv.mkDerivation rec { --enable-last --enable-mesg --disable-use-tty-group - --enable-fs-paths-default=/var/setuid-wrappers:/var/run/current-system/sw/bin:/sbin + --enable-fs-paths-default=/run/wrappers/bin:/var/run/current-system/sw/bin:/sbin ${if ncurses == null then "--without-ncurses" else ""} ${if systemd == null then "" else '' --with-systemd diff --git a/pkgs/servers/interlock/default.nix b/pkgs/servers/interlock/default.nix index 82ed92084df..a0b59d332a3 100644 --- a/pkgs/servers/interlock/default.nix +++ b/pkgs/servers/interlock/default.nix @@ -30,7 +30,7 @@ buildGoPackage rec { -e 's|/bin/chown|${coreutils}/bin/chown|' \ -e 's|/bin/date|${coreutils}/bin/date|' \ -e 's|/sbin/poweroff|${systemd}/sbin/poweroff|' \ - -e 's|/usr/bin/sudo|/var/setuid-wrappers/sudo|' \ + -e 's|/usr/bin/sudo|/run/wrappers/bin/sudo|' \ -e 's|/sbin/cryptsetup|${cryptsetup}/bin/cryptsetup|' ''; } diff --git a/pkgs/servers/mail/petidomo/default.nix b/pkgs/servers/mail/petidomo/default.nix index 3ecb00b64fc..395f3ded7fd 100644 --- a/pkgs/servers/mail/petidomo/default.nix +++ b/pkgs/servers/mail/petidomo/default.nix @@ -1,4 +1,4 @@ -{ stdenv, fetchurl, flex, bison, sendmailPath ? "/var/setuid-wrappers/sendmail" }: +{ stdenv, fetchurl, flex, bison, sendmailPath ? "/run/wrappers/bin/sendmail" }: stdenv.mkDerivation rec { name = "petidomo-4.3"; diff --git a/pkgs/servers/monitoring/nagios/plugins/official-2.x.nix b/pkgs/servers/monitoring/nagios/plugins/official-2.x.nix index 897182fe225..1ea6f88084d 100644 --- a/pkgs/servers/monitoring/nagios/plugins/official-2.x.nix +++ b/pkgs/servers/monitoring/nagios/plugins/official-2.x.nix @@ -16,8 +16,8 @@ stdenv.mkDerivation rec { # configured on the build machine). preConfigure= " configureFlagsArray=( - --with-ping-command='/var/setuid-wrappers/ping -n -U -w %d -c %d %s' - --with-ping6-command='/var/setuid-wrappers/ping6 -n -U -w %d -c %d %s' + --with-ping-command='/run/wrappers/bin/ping -n -U -w %d -c %d %s' + --with-ping6-command='/run/wrappers/bin/ping6 -n -U -w %d -c %d %s' ) "; diff --git a/pkgs/tools/X11/x11vnc/default.nix b/pkgs/tools/X11/x11vnc/default.nix index a8c249116c0..2d319cccf20 100644 --- a/pkgs/tools/X11/x11vnc/default.nix +++ b/pkgs/tools/X11/x11vnc/default.nix @@ -20,10 +20,10 @@ stdenv.mkDerivation rec { configureFlags="--mandir=$out/share/man" substituteInPlace x11vnc/unixpw.c \ - --replace '"/bin/su"' '"/var/setuid-wrappers/su"' \ + --replace '"/bin/su"' '"/run/wrappers/bin/su"' \ --replace '"/bin/true"' '"${coreutils}/bin/true"' - sed -i -e '/#!\/bin\/sh/a"PATH=${xorg.xdpyinfo}\/bin:${xorg.xauth}\/bin:$PATH\\n"' -e 's|/bin/su|/var/setuid-wrappers/su|g' x11vnc/ssltools.h + sed -i -e '/#!\/bin\/sh/a"PATH=${xorg.xdpyinfo}\/bin:${xorg.xauth}\/bin:$PATH\\n"' -e 's|/bin/su|/run/wrappers/bin/su|g' x11vnc/ssltools.h ''; meta = { diff --git a/pkgs/tools/admin/certbot/default.nix b/pkgs/tools/admin/certbot/default.nix index 8ff147faacc..3648cb2c136 100644 --- a/pkgs/tools/admin/certbot/default.nix +++ b/pkgs/tools/admin/certbot/default.nix @@ -31,7 +31,7 @@ python2Packages.buildPythonApplication rec { buildInputs = [ dialog ] ++ (with python2Packages; [ nose mock gnureadline ]); patchPhase = '' - substituteInPlace certbot/notify.py --replace "/usr/sbin/sendmail" "/var/setuid-wrappers/sendmail" + substituteInPlace certbot/notify.py --replace "/usr/sbin/sendmail" "/run/wrappers/bin/sendmail" substituteInPlace certbot/util.py --replace "sw_vers" "/usr/bin/sw_vers" ''; diff --git a/pkgs/tools/misc/debian-devscripts/default.nix b/pkgs/tools/misc/debian-devscripts/default.nix index 2fe9ec2fbe7..cbc7a2e7e46 100644 --- a/pkgs/tools/misc/debian-devscripts/default.nix +++ b/pkgs/tools/misc/debian-devscripts/default.nix @@ -2,7 +2,7 @@ , FileDesktopEntry, libxslt, docbook_xsl, makeWrapper , python3Packages , perlPackages, curl, gnupg, diffutils -, sendmailPath ? "/var/setuid-wrappers/sendmail" +, sendmailPath ? "/run/wrappers/bin/sendmail" }: let diff --git a/pkgs/tools/security/ecryptfs/default.nix b/pkgs/tools/security/ecryptfs/default.nix index 4981d8fa062..ab4867a4cc8 100644 --- a/pkgs/tools/security/ecryptfs/default.nix +++ b/pkgs/tools/security/ecryptfs/default.nix @@ -11,7 +11,7 @@ stdenv.mkDerivation rec { }; # TODO: replace wrapperDir below with from config.security.wrapperDir; - wrapperDir = "/var/setuid-wrappers"; + wrapperDir = "/run/wrappers/bin"; postPatch = '' FILES="$(grep -r '/bin/sh' src/utils -l; find src -name \*.c)" diff --git a/pkgs/tools/security/ecryptfs/helper.nix b/pkgs/tools/security/ecryptfs/helper.nix index 0d4b37a8efc..05327ad3a09 100644 --- a/pkgs/tools/security/ecryptfs/helper.nix +++ b/pkgs/tools/security/ecryptfs/helper.nix @@ -18,7 +18,7 @@ stdenv.mkDerivation rec { buildInputs = [ makeWrapper ]; - # Do not hardcode PATH to ${ecryptfs} as we need the script to invoke executables from /var/setuid-wrappers + # Do not hardcode PATH to ${ecryptfs} as we need the script to invoke executables from /run/wrappers/bin installPhase = '' mkdir -p $out/bin $out/libexec cp $src $out/libexec/ecryptfs-helper.py diff --git a/pkgs/tools/security/sudo/default.nix b/pkgs/tools/security/sudo/default.nix index d360bd8b17e..b8e0ebaa9bb 100644 --- a/pkgs/tools/security/sudo/default.nix +++ b/pkgs/tools/security/sudo/default.nix @@ -1,5 +1,5 @@ { stdenv, fetchurl, coreutils, pam, groff -, sendmailPath ? "/var/setuid-wrappers/sendmail" +, sendmailPath ? "/run/wrappers/bin/sendmail" , withInsults ? false }: diff --git a/pkgs/tools/system/at/default.nix b/pkgs/tools/system/at/default.nix index 9991adf4013..185645763fd 100644 --- a/pkgs/tools/system/at/default.nix +++ b/pkgs/tools/system/at/default.nix @@ -1,4 +1,4 @@ -{ fetchurl, stdenv, bison, flex, pam, sendmailPath ? "/var/setuid-wrappers/sendmail" }: +{ fetchurl, stdenv, bison, flex, pam, sendmailPath ? "/run/wrappers/bin/sendmail" }: stdenv.mkDerivation { name = "at-3.1.16"; diff --git a/pkgs/tools/system/cron/default.nix b/pkgs/tools/system/cron/default.nix index 3d03f19cb6f..dec1bacd741 100644 --- a/pkgs/tools/system/cron/default.nix +++ b/pkgs/tools/system/cron/default.nix @@ -23,7 +23,7 @@ stdenv.mkDerivation { #define _PATH_SENDMAIL "${sendmailPath}" #undef _PATH_DEFPATH - #define _PATH_DEFPATH "/var/setuid-wrappers:/nix/var/nix/profiles/default/bin:/nix/var/nix/profiles/default/sbin:/run/current-system/sw/bin:/run/current-system/sw/sbin:/usr/bin:/bin" + #define _PATH_DEFPATH "/run/wrappers/bin:/nix/var/nix/profiles/default/bin:/nix/var/nix/profiles/default/sbin:/run/current-system/sw/bin:/run/current-system/sw/sbin:/usr/bin:/bin" __EOT__ # Implicit saved uids do not work here due to way NixOS uses setuid wrappers diff --git a/pkgs/tools/system/ts/default.nix b/pkgs/tools/system/ts/default.nix index cad1230ac87..97b35378673 100644 --- a/pkgs/tools/system/ts/default.nix +++ b/pkgs/tools/system/ts/default.nix @@ -1,5 +1,5 @@ {stdenv, fetchurl, -sendmailPath ? "/var/setuid-wrappers/sendmail" }: +sendmailPath ? "/run/wrappers/bin/sendmail" }: stdenv.mkDerivation rec {