diff --git a/etc/default.nix b/etc/default.nix index 095318bb4355..6306dd4edaf0 100644 --- a/etc/default.nix +++ b/etc/default.nix @@ -39,7 +39,7 @@ let nixEnvVars = config.nix.envVars; modulesTree = config.system.modulesTree; nssModulesPath = config.system.nssModules.path; - wrapperDir = config.system.wrapperDir; + wrapperDir = config.security.wrapperDir; systemPath = config.system.path; binsh = config.system.build.binsh; diff --git a/helpers/setuid/default.nix b/helpers/setuid/default.nix deleted file mode 100644 index 362bd937cc49..000000000000 --- a/helpers/setuid/default.nix +++ /dev/null @@ -1,10 +0,0 @@ -{stdenv, wrapperDir}: - -stdenv.mkDerivation { - name = "setuid-wrapper"; - buildCommand = '' - ensureDir $out/bin - gcc -Wall -O2 -DWRAPPER_DIR=\"${wrapperDir}\" ${./setuid-wrapper.c} -o $out/bin/setuid-wrapper - strip -s $out/bin/setuid-wrapper - ''; -} diff --git a/helpers/setuid/setuid-wrapper.c b/modules/security/setuid-wrapper.c similarity index 100% rename from helpers/setuid/setuid-wrapper.c rename to modules/security/setuid-wrapper.c diff --git a/modules/security/setuid-wrappers.nix b/modules/security/setuid-wrappers.nix index 367a6d172c15..d7f0157a0e80 100644 --- a/modules/security/setuid-wrappers.nix +++ b/modules/security/setuid-wrappers.nix @@ -1,47 +1,127 @@ {pkgs, config, ...}: +with pkgs.lib; + let - inherit (pkgs.lib) mergeOneOption mkOption mkIf; + + options = { + security = { + setuidPrograms = mkOption { + default = [ + "passwd" "su" "crontab" "ping" "ping6" + "fusermount" "wodim" "cdrdao" "growisofs" + ]; + description = '' + Only the programs from system path listed her will be made setuid root + (through a wrapper program). It's better to set + . + ''; + }; + + # !!! obsolete + extraSetuidPrograms = mkOption { + default = []; + example = ["fusermount"]; + description = '' + This option lists additional programs that must be made setuid + root. + ''; + }; + + setuidOwners = mkOption { + default = []; + example = [{ + program = "sendmail"; + owner = "nobody"; + group = "postdrop"; + setuid = false; + setgid = true; + }]; + description = '' + This option allows the ownership and permissions on the setuid + wrappers for specific programs to be overriden from the + default (setuid root, but not setgid root). + ''; + }; + + wrapperDir = mkOption { + default = "/var/setuid-wrappers"; + description = '' + This option defines the path to the setuid wrappers. It + should generally not be overriden. + ''; + }; + }; + }; + + setuidWrapper = pkgs.stdenv.mkDerivation { + name = "setuid-wrapper"; + buildCommand = '' + ensureDir $out/bin + gcc -Wall -O2 -DWRAPPER_DIR=\"${config.security.wrapperDir}\" ${./setuid-wrapper.c} -o $out/bin/setuid-wrapper + strip -s $out/bin/setuid-wrapper + ''; + }; + in { - security = { - setuidPrograms = mkOption { - default = [ - "passwd" "su" "crontab" "ping" "ping6" - "fusermount" "wodim" "cdrdao" "growisofs" - ]; - description = " - Only the programs from system path listed her will be made setuid root - (through a wrapper program). It's better to set - . - "; - }; + require = [options]; - extraSetuidPrograms = mkOption { - default = []; - example = ["fusermount"]; - description = " - This option lists additional programs that must be made setuid - root. - "; - }; + system = { + activationScripts = { + setuid = + let + setuidPrograms = builtins.toString ( + config.security.setuidPrograms ++ + config.security.extraSetuidPrograms ++ + map (x: x.program) config.security.setuidOwners + ); - setuidOwners = mkOption { - default = []; - example = [{ - program = "sendmail"; - owner = "nodody"; - group = "postdrop"; - setuid = false; - setgid = true; - }]; - description = '' - List of non-trivial setuid programs from system path, like Postfix sendmail. Default - should probably be nobody:nogroup:false:false - if you are bothering - doing anything with a setuid program, "root.root u+s g-s" is not what - you are aiming at.. - ''; + adjustSetuidOwner = concatStrings (map + (_entry: let entry = { + owner = "nobody"; + group = "nogroup"; + setuid = false; + setgid = false; + } //_entry; in + '' + chown ${entry.owner}.${entry.group} $wrapperDir/${entry.program} + chmod u${if entry.setuid then "+" else "-"}s $wrapperDir/${entry.program} + chmod g${if entry.setgid then "+" else "-"}s $wrapperDir/${entry.program} + '') + config.security.setuidOwners); + + in fullDepEntry '' + # Look in the system path and in the default profile for + # programs to be wrapped. However, having setuid programs + # in a profile is problematic, since the NixOS activation + # script won't be rerun automatically when you install a + # wrappable program in the profile with nix-env. + SETUID_PATH=/nix/var/nix/profiles/default/sbin:/nix/var/nix/profiles/default/bin:${config.system.path}/bin:${config.system.path}/sbin + + wrapperDir=${config.security.wrapperDir} + if test -d $wrapperDir; then rm -f $wrapperDir/*; fi # */ + mkdir -p $wrapperDir + + for i in ${setuidPrograms}; do + program=$(PATH=$SETUID_PATH type -tP $i) + if test -z "$program"; then + # XXX: It would be preferable to detect this problem before + # `activate-configuration' is invoked. + #echo "WARNING: No executable named \`$i' was found" >&2 + #echo "WARNING: but \`$i' was specified as a setuid program." >&2 + true + else + cp ${setuidWrapper}/bin/setuid-wrapper $wrapperDir/$i + echo -n "$program" > $wrapperDir/$i.real + chown root.root $wrapperDir/$i + chmod 4755 $wrapperDir/$i + fi + done + + ${adjustSetuidOwner} + '' [ "defaultPath" "users" ]; }; }; } diff --git a/system/system-options.nix b/system/system-options.nix index ca305cfddf46..1065d5721eb1 100644 --- a/system/system-options.nix +++ b/system/system-options.nix @@ -26,22 +26,14 @@ let shell = mkOption { default = "/var/run/current-system/sw/bin/bash"; description = '' - You should not redefine this option unless you want to change the - bash version for security issues. + This option defines the path to the Bash shell. It should + generally not be overriden. ''; merge = list: assert list != [] && builtins.tail list == []; builtins.head list; }; - wrapperDir = mkOption { - default = "/var/setuid-wrappers"; - description = '' - You should not redefine this option unless you want to change the - path for security issues. - ''; - }; - overridePath = mkOption { default = []; description = '' @@ -75,7 +67,6 @@ in let inherit (pkgs.stringsWithDeps) noDepEntry fullDepEntry packEntry; inherit (pkgs.lib) mapRecordFlatten; - in { @@ -103,14 +94,14 @@ in let path = [ pkgs.coreutils pkgs.gnugrep pkgs.findutils pkgs.glibc # needed for getent - pkgs.glibcLocales # needed for getent pkgs.pwdutils + pkgs.nettools # needed for hostname ]; in noDepEntry '' - export PATH=/empty - for i in ${toString path}; do - PATH=$PATH:$i/bin:$i/sbin; - done - ''; + export PATH=/empty + for i in ${toString path}; do + PATH=$PATH:$i/bin:$i/sbin; + done + ''; stdio = fullDepEntry '' # Needed by some programs. @@ -220,64 +211,6 @@ in "users" # nixbld group ]; - path = fullDepEntry '' - PATH=${config.system.path}/bin:${config.system.path}/sbin:$PATH - '' [ "defaultPath" ]; - - setuid = - let - setuidPrograms = builtins.toString ( - config.security.setuidPrograms ++ - config.security.extraSetuidPrograms ++ - map (x: x.program) config.security.setuidOwners - ); - - adjustSetuidOwner = pkgs.lib.concatStrings (map - (_entry: let entry = { - owner = "nobody"; - group = "nogroup"; - setuid = false; - setgid = false; - } //_entry; in - '' - chown ${entry.owner}.${entry.group} $wrapperDir/${entry.program} - chmod u${if entry.setuid then "+" else "-"}s $wrapperDir/${entry.program} - chmod g${if entry.setgid then "+" else "-"}s $wrapperDir/${entry.program} - '') - config.security.setuidOwners); - - in fullDepEntry '' - # Make a few setuid programs work. - save_PATH="$PATH" - - # Add the default profile to the search path for setuid executables. - PATH="/nix/var/nix/profiles/default/sbin:$PATH" - PATH="/nix/var/nix/profiles/default/bin:$PATH" - - wrapperDir=${config.system.wrapperDir} - if test -d $wrapperDir; then rm -f $wrapperDir/*; fi # */ - mkdir -p $wrapperDir - for i in ${setuidPrograms}; do - program=$(type -tp $i) - if test -z "$program"; then - # XXX: It would be preferable to detect this problem before - # `activate-configuration' is invoked. - #echo "WARNING: No executable named \`$i' was found" >&2 - #echo "WARNING: but \`$i' was specified as a setuid program." >&2 - true - else - cp "$(type -tp setuid-wrapper)" $wrapperDir/$i - echo -n "$program" > $wrapperDir/$i.real - chown root.root $wrapperDir/$i - chmod 4755 $wrapperDir/$i - fi - done - - ${adjustSetuidOwner} - - PATH="$save_PATH" - '' [ "path" "users" ]; - hostname = fullDepEntry '' # Set the host name. Don't clear it if it's not configured in the # NixOS configuration, since it may have been set by dhclient in the @@ -290,7 +223,7 @@ in hostname "" fi ''} - '' [ "path" ]; + '' [ "defaultPath" ]; # The activation has to be done at the end. This is forced at the apply # function of activationScripts option @@ -302,7 +235,7 @@ in ln -sfn "$(readlink -f "$systemConfig")" /var/run/current-system # Prevent the current configuration from being garbage-collected. - ln -sfn /var/run/current-system /nix/var/nix/gcroots/current-system + ln -sfn /var/run/current-system /nix/var/nix/gcroots/current-system ''; }; }; diff --git a/system/system.nix b/system/system.nix index 06a212df2d9e..eaa41c720d8e 100644 --- a/system/system.nix +++ b/system/system.nix @@ -34,8 +34,6 @@ rec { kernel = kernelPackages.kernel; - modulesTree = config.system.modulesTree; - # The initial ramdisk. initialRamdiskStuff = import ../modules/system/boot/stage-1.nix { @@ -61,10 +59,6 @@ rec { modprobe = config.system.sbin.modprobe; - # Environment variables for running Nix. - nixEnvVars = config.nix.envVars; - - # The static parts of /etc. etc = config.system.build.etc; @@ -73,16 +67,6 @@ rec { fontDir = config.system.build.x11Fonts; - # The wrapper setuid programs (since we can't have setuid programs - # in the Nix store). - wrapperDir = config.system.wrapperDir; - - setuidWrapper = import ../helpers/setuid { - inherit (pkgs) stdenv; - inherit wrapperDir; - }; - - # A patched `mount' command that looks in a directory in the Nix # store instead of in /sbin for mount helpers (like mount.ntfs-3g or # mount.cifs). @@ -104,7 +88,6 @@ rec { nixosTools.nixosCheckout nixosTools.nixosHardwareScan nixosTools.nixosGenSeccureKeys - setuidWrapper ]; path = pkgs.lib.optionals (!config.environment.cleanStart) [