* Move the setuid wrappers activation scriptlet to

modules/security/setuid-wrappers.nix.
* Removed the "path" activation scriptlet.  The partial ordering was
  underspecified (there was nothing ensuring that it came near the end
  of the activation script), and it wasn't needed in any case.

svn path=/nixos/branches/modular-nixos/; revision=15726
This commit is contained in:
Eelco Dolstra 2009-05-25 15:36:57 +00:00
parent 278b15d840
commit c96f0d75f0
6 changed files with 127 additions and 141 deletions

View File

@ -39,7 +39,7 @@ let
nixEnvVars = config.nix.envVars; nixEnvVars = config.nix.envVars;
modulesTree = config.system.modulesTree; modulesTree = config.system.modulesTree;
nssModulesPath = config.system.nssModules.path; nssModulesPath = config.system.nssModules.path;
wrapperDir = config.system.wrapperDir; wrapperDir = config.security.wrapperDir;
systemPath = config.system.path; systemPath = config.system.path;
binsh = config.system.build.binsh; binsh = config.system.build.binsh;

View File

@ -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
'';
}

View File

@ -1,47 +1,127 @@
{pkgs, config, ...}: {pkgs, config, ...}:
with pkgs.lib;
let 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
<option>security.extraSetuidPrograms</option>.
'';
};
# !!! 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 in
{ {
security = { require = [options];
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
<option>security.extraSetuidPrograms</option>.
";
};
extraSetuidPrograms = mkOption { system = {
default = []; activationScripts = {
example = ["fusermount"]; setuid =
description = " let
This option lists additional programs that must be made setuid setuidPrograms = builtins.toString (
root. config.security.setuidPrograms ++
"; config.security.extraSetuidPrograms ++
}; map (x: x.program) config.security.setuidOwners
);
setuidOwners = mkOption { adjustSetuidOwner = concatStrings (map
default = []; (_entry: let entry = {
example = [{ owner = "nobody";
program = "sendmail"; group = "nogroup";
owner = "nodody"; setuid = false;
group = "postdrop"; setgid = false;
setuid = false; } //_entry; in
setgid = true; ''
}]; chown ${entry.owner}.${entry.group} $wrapperDir/${entry.program}
description = '' chmod u${if entry.setuid then "+" else "-"}s $wrapperDir/${entry.program}
List of non-trivial setuid programs from system path, like Postfix sendmail. Default chmod g${if entry.setgid then "+" else "-"}s $wrapperDir/${entry.program}
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 config.security.setuidOwners);
you are aiming at..
''; 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" ];
}; };
}; };
} }

View File

@ -26,22 +26,14 @@ let
shell = mkOption { shell = mkOption {
default = "/var/run/current-system/sw/bin/bash"; default = "/var/run/current-system/sw/bin/bash";
description = '' description = ''
You should not redefine this option unless you want to change the This option defines the path to the Bash shell. It should
bash version for security issues. generally not be overriden.
''; '';
merge = list: merge = list:
assert list != [] && builtins.tail list == []; assert list != [] && builtins.tail list == [];
builtins.head 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 { overridePath = mkOption {
default = []; default = [];
description = '' description = ''
@ -75,7 +67,6 @@ in
let let
inherit (pkgs.stringsWithDeps) noDepEntry fullDepEntry packEntry; inherit (pkgs.stringsWithDeps) noDepEntry fullDepEntry packEntry;
inherit (pkgs.lib) mapRecordFlatten; inherit (pkgs.lib) mapRecordFlatten;
in in
{ {
@ -103,14 +94,14 @@ in
let path = [ let path = [
pkgs.coreutils pkgs.gnugrep pkgs.findutils pkgs.coreutils pkgs.gnugrep pkgs.findutils
pkgs.glibc # needed for getent pkgs.glibc # needed for getent
pkgs.glibcLocales # needed for getent
pkgs.pwdutils pkgs.pwdutils
pkgs.nettools # needed for hostname
]; in noDepEntry '' ]; in noDepEntry ''
export PATH=/empty export PATH=/empty
for i in ${toString path}; do for i in ${toString path}; do
PATH=$PATH:$i/bin:$i/sbin; PATH=$PATH:$i/bin:$i/sbin;
done done
''; '';
stdio = fullDepEntry '' stdio = fullDepEntry ''
# Needed by some programs. # Needed by some programs.
@ -220,64 +211,6 @@ in
"users" # nixbld group "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 '' hostname = fullDepEntry ''
# Set the host name. Don't clear it if it's not configured in the # 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 # NixOS configuration, since it may have been set by dhclient in the
@ -290,7 +223,7 @@ in
hostname "" hostname ""
fi fi
''} ''}
'' [ "path" ]; '' [ "defaultPath" ];
# The activation has to be done at the end. This is forced at the apply # The activation has to be done at the end. This is forced at the apply
# function of activationScripts option # function of activationScripts option
@ -302,7 +235,7 @@ in
ln -sfn "$(readlink -f "$systemConfig")" /var/run/current-system ln -sfn "$(readlink -f "$systemConfig")" /var/run/current-system
# Prevent the current configuration from being garbage-collected. # 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
''; '';
}; };
}; };

View File

@ -34,8 +34,6 @@ rec {
kernel = kernelPackages.kernel; kernel = kernelPackages.kernel;
modulesTree = config.system.modulesTree;
# The initial ramdisk. # The initial ramdisk.
initialRamdiskStuff = import ../modules/system/boot/stage-1.nix { initialRamdiskStuff = import ../modules/system/boot/stage-1.nix {
@ -61,10 +59,6 @@ rec {
modprobe = config.system.sbin.modprobe; modprobe = config.system.sbin.modprobe;
# Environment variables for running Nix.
nixEnvVars = config.nix.envVars;
# The static parts of /etc. # The static parts of /etc.
etc = config.system.build.etc; etc = config.system.build.etc;
@ -73,16 +67,6 @@ rec {
fontDir = config.system.build.x11Fonts; 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 # 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 # store instead of in /sbin for mount helpers (like mount.ntfs-3g or
# mount.cifs). # mount.cifs).
@ -104,7 +88,6 @@ rec {
nixosTools.nixosCheckout nixosTools.nixosCheckout
nixosTools.nixosHardwareScan nixosTools.nixosHardwareScan
nixosTools.nixosGenSeccureKeys nixosTools.nixosGenSeccureKeys
setuidWrapper
]; ];
path = path =
pkgs.lib.optionals (!config.environment.cleanStart) [ pkgs.lib.optionals (!config.environment.cleanStart) [