at 16.09-beta 4.5 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 inherit (config.security) wrapperDir; 8 9 setuidWrapper = pkgs.stdenv.mkDerivation { 10 name = "setuid-wrapper"; 11 unpackPhase = "true"; 12 installPhase = '' 13 mkdir -p $out/bin 14 cp ${./setuid-wrapper.c} setuid-wrapper.c 15 gcc -Wall -O2 -DWRAPPER_DIR=\"/run/setuid-wrapper-dirs\" \ 16 setuid-wrapper.c -o $out/bin/setuid-wrapper 17 ''; 18 }; 19 20in 21 22{ 23 24 ###### interface 25 26 options = { 27 28 security.setuidPrograms = mkOption { 29 type = types.listOf types.str; 30 default = []; 31 example = ["passwd"]; 32 description = '' 33 The Nix store cannot contain setuid/setgid programs directly. 34 For this reason, NixOS can automatically generate wrapper 35 programs that have the necessary privileges. This option 36 lists the names of programs in the system environment for 37 which setuid root wrappers should be created. 38 ''; 39 }; 40 41 security.setuidOwners = mkOption { 42 type = types.listOf types.attrs; 43 default = []; 44 example = 45 [ { program = "sendmail"; 46 owner = "nobody"; 47 group = "postdrop"; 48 setuid = false; 49 setgid = true; 50 permissions = "u+rx,g+x,o+x"; 51 } 52 ]; 53 description = '' 54 This option allows the ownership and permissions on the setuid 55 wrappers for specific programs to be overridden from the 56 default (setuid root, but not setgid root). 57 ''; 58 }; 59 60 security.wrapperDir = mkOption { 61 internal = true; 62 type = types.path; 63 default = "/var/setuid-wrappers"; 64 description = '' 65 This option defines the path to the setuid wrappers. It 66 should generally not be overriden. Some packages in Nixpkgs 67 expect that <option>wrapperDir</option> is 68 <filename>/var/setuid-wrappers</filename>. 69 ''; 70 }; 71 72 }; 73 74 75 ###### implementation 76 77 config = { 78 79 security.setuidPrograms = [ "fusermount" ]; 80 81 system.activationScripts.setuid = 82 let 83 setuidPrograms = 84 (map (x: { program = x; owner = "root"; group = "root"; setuid = true; }) 85 config.security.setuidPrograms) 86 ++ config.security.setuidOwners; 87 88 makeSetuidWrapper = 89 { program 90 , source ? "" 91 , owner ? "nobody" 92 , group ? "nogroup" 93 , setuid ? false 94 , setgid ? false 95 , permissions ? "u+rx,g+x,o+x" 96 }: 97 98 '' 99 if ! source=${if source != "" then source else "$(readlink -f $(PATH=$SETUID_PATH type -tP ${program}))"}; then 100 # If we can't find the program, fall back to the 101 # system profile. 102 source=/nix/var/nix/profiles/default/bin/${program} 103 fi 104 105 cp ${setuidWrapper}/bin/setuid-wrapper $wrapperDir/${program} 106 echo -n "$source" > $wrapperDir/${program}.real 107 chmod 0000 $wrapperDir/${program} # to prevent races 108 chown ${owner}.${group} $wrapperDir/${program} 109 chmod "u${if setuid then "+" else "-"}s,g${if setgid then "+" else "-"}s,${permissions}" $wrapperDir/${program} 110 ''; 111 112 in stringAfter [ "users" ] 113 '' 114 # Look in the system path and in the default profile for 115 # programs to be wrapped. 116 SETUID_PATH=${config.system.path}/bin:${config.system.path}/sbin 117 118 mkdir -p /run/setuid-wrapper-dirs 119 wrapperDir=$(mktemp --directory --tmpdir=/run/setuid-wrapper-dirs setuid-wrappers.XXXXXXXXXX) 120 121 ${concatMapStrings makeSetuidWrapper setuidPrograms} 122 123 if [ -L ${wrapperDir} ]; then 124 # Atomically replace the symlink 125 # See https://axialcorps.com/2013/07/03/atomically-replacing-files-and-directories/ 126 old=$(readlink ${wrapperDir}) 127 ln --symbolic --force --no-dereference $wrapperDir ${wrapperDir}-tmp 128 mv --no-target-directory ${wrapperDir}-tmp ${wrapperDir} 129 rm --force --recursive $old 130 elif [ -d ${wrapperDir} ]; then 131 # Compatibility with old state, just remove the folder and symlink 132 rm -f ${wrapperDir}/* 133 # if it happens to be a tmpfs 134 umount ${wrapperDir} || true 135 rm -d ${wrapperDir} 136 ln -d --symbolic $wrapperDir ${wrapperDir} 137 else 138 # For initial setup 139 ln --symbolic $wrapperDir ${wrapperDir} 140 fi 141 ''; 142 143 }; 144 145}