diff options
author | Joachim Fasting <joachifm@users.noreply.github.com> | 2016-06-14 03:52:50 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-06-14 03:52:50 +0200 |
commit | 886c03ad2ec5fed59831bd552d34ba03327f2ac7 (patch) | |
tree | c201f8766bb9e8b97ada0f1852cfcb99258ea8ae /nixos | |
parent | 3123c7df37ac2fa69bc3fa4c561ac94d529d2fc5 (diff) | |
parent | 7bda8f0a8fc38e3cccd565521342ec9aaeffb297 (diff) | |
download | nixlib-886c03ad2ec5fed59831bd552d34ba03327f2ac7.tar nixlib-886c03ad2ec5fed59831bd552d34ba03327f2ac7.tar.gz nixlib-886c03ad2ec5fed59831bd552d34ba03327f2ac7.tar.bz2 nixlib-886c03ad2ec5fed59831bd552d34ba03327f2ac7.tar.lz nixlib-886c03ad2ec5fed59831bd552d34ba03327f2ac7.tar.xz nixlib-886c03ad2ec5fed59831bd552d34ba03327f2ac7.tar.zst nixlib-886c03ad2ec5fed59831bd552d34ba03327f2ac7.zip |
Merge pull request #16107 from joachifm/grsec-ng
Rework grsecurity support
Diffstat (limited to 'nixos')
-rw-r--r-- | nixos/modules/config/users-groups.nix | 2 | ||||
-rw-r--r-- | nixos/modules/misc/ids.nix | 2 | ||||
-rw-r--r-- | nixos/modules/rename.nix | 20 | ||||
-rw-r--r-- | nixos/modules/security/grsecurity.nix | 376 | ||||
-rw-r--r-- | nixos/tests/grsecurity.nix | 40 |
5 files changed, 144 insertions, 296 deletions
diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix index e643b2d059b5..8231907d7999 100644 --- a/nixos/modules/config/users-groups.nix +++ b/nixos/modules/config/users-groups.nix @@ -468,7 +468,6 @@ in { home = "/root"; shell = mkDefault cfg.defaultUserShell; group = "root"; - extraGroups = [ "grsecurity" ]; initialHashedPassword = mkDefault config.security.initialRootPassword; }; nobody = { @@ -497,7 +496,6 @@ in { nixbld.gid = ids.gids.nixbld; utmp.gid = ids.gids.utmp; adm.gid = ids.gids.adm; - grsecurity.gid = ids.gids.grsecurity; input.gid = ids.gids.input; }; diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index d421167c859c..61c49f07abbb 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -147,7 +147,6 @@ foundationdb = 118; newrelic = 119; starbound = 120; - #grsecurity = 121; # unused hydra = 122; spiped = 123; teamspeak = 124; @@ -396,7 +395,6 @@ foundationdb = 118; newrelic = 119; starbound = 120; - grsecurity = 121; hydra = 122; spiped = 123; teamspeak = 124; diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 3440261c3965..634f91a275d3 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -114,6 +114,26 @@ with lib; (mkRenamedOptionModule [ "services" "iodined" "extraConfig" ] [ "services" "iodine" "server" "extraConfig" ]) (mkRemovedOptionModule [ "services" "iodined" "client" ]) + # Grsecurity + (mkRemovedOptionModule [ "security" "grsecurity" "kernelPatch" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "mode" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "priority" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "system" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "virtualisationConfig" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "hardwareVirtualisation" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "virtualisationSoftware" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "sysctl" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "denyChrootChmod" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "denyChrootCaps" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "denyUSB" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "restrictProc" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "restrictProcWithGroup" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "unrestrictProcGid" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "disableRBAC" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "disableSimultConnect" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "verboseVersion" ]) + (mkRemovedOptionModule [ "security" "grsecurity" "config" "kernelExtraConfig" ]) + # Options that are obsolete and have no replacement. (mkRemovedOptionModule [ "boot" "initrd" "luks" "enable" ]) (mkRemovedOptionModule [ "programs" "bash" "enable" ]) diff --git a/nixos/modules/security/grsecurity.nix b/nixos/modules/security/grsecurity.nix index 3f24118ea1cb..9d0249820d5d 100644 --- a/nixos/modules/security/grsecurity.nix +++ b/nixos/modules/security/grsecurity.nix @@ -1,312 +1,122 @@ -{ config, lib, pkgs, ... }: +{ config, pkgs, lib, ... }: with lib; let cfg = config.security.grsecurity; - - customGrsecPkg = - (import ../../../pkgs/build-support/grsecurity { - grsecOptions = cfg; - inherit pkgs lib; - }).grsecPackage; + grsecLockPath = "/proc/sys/kernel/grsecurity/grsec_lock"; + + # Ascertain whether ZFS is required for booting the system; grsecurity is + # currently incompatible with ZFS, rendering the system unbootable. + zfsNeededForBoot = filter + (fs: (fs.neededForBoot + || elem fs.mountPoint [ "/" "/nix" "/nix/store" "/var" "/var/log" "/var/lib" "/etc" ]) + && fs.fsType == "zfs") + (attrValues config.fileSystems) != []; in -{ - options = { - security.grsecurity = { - enable = mkOption { - type = types.bool; - default = false; - description = '' - Enable grsecurity support. This enables advanced exploit - hardening for the Linux kernel, and adds support for - administrative Role-Based Acess Control (RBAC) via - <literal>gradm</literal>. It also includes traditional - utilities for PaX. - ''; - }; - - kernelPatch = mkOption { - type = types.attrs; - example = lib.literalExample "pkgs.kernelPatches.grsecurity_4_1"; - description = '' - Grsecurity patch to use. - ''; - }; - - config = { - mode = mkOption { - type = types.enum [ "auto" "custom" ]; - default = "auto"; - description = '' - grsecurity configuration mode. This specifies whether - grsecurity is auto-configured or otherwise completely - manually configured. - ''; - }; - - priority = mkOption { - type = types.enum [ "security" "performance" ]; - default = "security"; - description = '' - grsecurity configuration priority. This specifies whether - the kernel configuration should emphasize speed or - security. - ''; - }; - - system = mkOption { - type = types.enum [ "desktop" "server" ]; - default = "desktop"; - description = '' - grsecurity system configuration. - ''; - }; - virtualisationConfig = mkOption { - type = types.nullOr (types.enum [ "host" "guest" ]); - default = null; - description = '' - grsecurity virtualisation configuration. This specifies - the virtualisation role of the machine - that is, whether - it will be a virtual machine guest, a virtual machine - host, or neither. - ''; - }; - - hardwareVirtualisation = mkOption { - type = types.nullOr types.bool; - default = null; - example = true; - description = '' - grsecurity hardware virtualisation configuration. Set to - <literal>true</literal> if your machine supports hardware - accelerated virtualisation. - ''; - }; - - virtualisationSoftware = mkOption { - type = types.nullOr (types.enum [ "kvm" "xen" "vmware" "virtualbox" ]); - default = null; - description = '' - Configure grsecurity for use with this virtualisation software. - ''; - }; - - sysctl = mkOption { - type = types.bool; - default = false; - description = '' - If true, then set <literal>GRKERN_SYSCTL y</literal>. If - enabled then grsecurity can be controlled using sysctl - (and turned off). You are advised to *never* enable this, - but if you do, make sure to always set the sysctl - <literal>kernel.grsecurity.grsec_lock</literal> to - non-zero as soon as all sysctl options are set. *THIS IS - EXTREMELY IMPORTANT*! - ''; - }; - - denyChrootChmod = mkOption { - type = types.bool; - default = false; - description = '' - If true, then set <literal>GRKERN_CHROOT_CHMOD - y</literal>. If enabled, this denies processes inside a - chroot from setting the suid or sgid bits using - <literal>chmod</literal> or <literal>fchmod</literal>. - - By default this protection is disabled - it makes it - impossible to use Nix to build software on your system, - which is what most users want. +{ + options.security.grsecurity = { + + enable = mkEnableOption "Grsecurity/PaX"; + + lockTunables = mkOption { + type = types.bool; + example = false; + default = true; + description = '' + Whether to automatically lock grsecurity tunables + (<option>boot.kernel.sysctl."kernel.grsecurity.*"</option>). Disable + this to allow configuration of grsecurity features while the system is + running. The lock can be manually engaged by activating the + <literal>grsec-lock</literal> service unit. + ''; + }; - If you are using NixOps to deploy your software to a - remote machine, you're encouraged to enable this as you - won't need to compile code. - ''; - }; + }; - denyChrootCaps = mkOption { - type = types.bool; - default = false; - description = '' - Whether to lower capabilities of all processes within a chroot, - preventing commands that require <literal>CAP_SYS_ADMIN</literal>. + config = mkIf cfg.enable { - This protection is disabled by default because it breaks - <literal>nixos-rebuild</literal>. Whenever possible, it is - highly recommended to enable this protection. - ''; - }; + # Allow the user to select a different package set, subject to the stated + # required kernel config + boot.kernelPackages = mkDefault pkgs.linuxPackages_grsec_nixos; - denyUSB = mkOption { - type = types.bool; - default = false; - description = '' - If true, then set <literal>GRKERNSEC_DENYUSB y</literal>. + system.requiredKernelConfig = with config.lib.kernelConfig; + [ (isEnabled "GRKERNSEC") + (isEnabled "PAX") + (isYES "GRKERNSEC_SYSCTL") + (isYES "GRKERNSEC_SYSCTL_DISTRO") + ]; - This enables a sysctl with name - <literal>kernel.grsecurity.deny_new_usb</literal>. Setting - its value to <literal>1</literal> will prevent any new USB - devices from being recognized by the OS. Any attempted - USB device insertion will be logged. + # Crashing on an overflow in kernel land is user unfriendly and may prevent + # the system from booting, which is too severe for our use case. + boot.kernelParams = [ "pax_size_overflow_report_only" ]; - This option is intended to be used against custom USB - devices designed to exploit vulnerabilities in various USB - device drivers. - ''; - }; + # Install PaX related utillities into the system profile. Eventually, we + # also want to include gradm here. + environment.systemPackages = with pkgs; [ paxctl pax-utils ]; - restrictProc = mkOption { - type = types.bool; - default = false; - description = '' - If true, then set <literal>GRKERN_PROC_USER - y</literal>. This restricts non-root users to only viewing - their own processes and restricts network-related - information, kernel symbols, and module information. - ''; - }; + # Install rules for the grsec device node + services.udev.packages = [ pkgs.gradm ]; - restrictProcWithGroup = mkOption { - type = types.bool; - default = true; - description = '' - If true, then set <literal>GRKERN_PROC_USERGROUP - y</literal>. This is similar to - <literal>restrictProc</literal> except it allows a special - group (specified by <literal>unrestrictProcGid</literal>) - to still access otherwise classified information in - <literal>/proc</literal>. - ''; - }; + # This service unit is responsible for locking the Grsecurity tunables. The + # unit is always defined, but only activated on bootup if lockTunables is + # toggled. When lockTunables is toggled, failure to activate the unit will + # enter emergency mode. The intent is to make it difficult to silently + # enter multi-user mode without having locked the tunables. Some effort is + # made to ensure that starting the unit is an idempotent operation. + systemd.services.grsec-lock = { + description = "Lock grsecurity tunables"; - unrestrictProcGid = mkOption { - type = types.int; - default = config.ids.gids.grsecurity; - description = '' - If set, specifies a GID which is exempt from - <literal>/proc</literal> restrictions (set by - <literal>GRKERN_PROC_USERGROUP</literal>). By default, - this is set to the GID for <literal>grsecurity</literal>, - a predefined NixOS group, which the - <literal>root</literal> account is a member of. You may - conveniently add other users to this group if you need - access to <literal>/proc</literal> - ''; - }; + wantedBy = optional cfg.lockTunables "multi-user.target"; - disableRBAC = mkOption { - type = types.bool; - default = false; - description = '' - If true, then set <literal>GRKERN_NO_RBAC - y</literal>. This disables the - <literal>/dev/grsec</literal> device, which in turn - disables the RBAC system (and <literal>gradm</literal>). - ''; - }; + wants = [ "local-fs.target" "systemd-sysctl.service" ]; + after = [ "local-fs.target" "systemd-sysctl.service" ]; + conflicts = [ "shutdown.target" ]; - disableSimultConnect = mkOption { - type = types.bool; - default = false; - description = '' - Disable TCP simultaneous connect. The TCP simultaneous connect - feature allows two clients to connect without either of them - entering the listening state. This feature of the TCP specification - is claimed to enable an attacker to deny the target access to a given - server by guessing the source port the target would use to make the - connection. + restartIfChanged = false; - This option is OFF by default because TCP simultaneous connect has - some legitimate uses. Enable this option if you know what this TCP - feature is for and know that you do not need it. - ''; - }; + script = '' + if ${pkgs.gnugrep}/bin/grep -Fq 0 ${grsecLockPath} ; then + echo -n 1 > ${grsecLockPath} + fi + ''; - verboseVersion = mkOption { - type = types.bool; - default = false; - description = "Use verbose version in kernel localversion."; - }; + unitConfig = { + ConditionPathIsReadWrite = grsecLockPath; + DefaultDependencies = false; + } // optionalAttrs cfg.lockTunables { + OnFailure = "emergency.target"; + }; - kernelExtraConfig = mkOption { - type = types.str; - default = ""; - description = "Extra kernel configuration parameters."; - }; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; }; }; - }; - config = mkIf cfg.enable { - assertions = - [ - { assertion = (cfg.config.restrictProc -> !cfg.config.restrictProcWithGroup) || - (cfg.config.restrictProcWithGroup -> !cfg.config.restrictProc); - message = "You cannot enable both restrictProc and restrictProcWithGroup"; - } - { assertion = config.boot.kernelPackages.kernel.features ? grsecurity - && config.boot.kernelPackages.kernel.features.grsecurity; - message = "grsecurity enabled, but kernel doesn't have grsec support"; - } - { assertion = (cfg.config.mode == "auto" && (cfg.config.virtualisationConfig != null)) -> - cfg.config.hardwareVirtualisation != null; - message = "when using auto grsec mode with virtualisation, you must specify if your hardware has virtualisation extensions"; - } - { assertion = (cfg.config.mode == "auto" && (cfg.config.virtualisationConfig != null)) -> - cfg.config.virtualisationSoftware != null; - message = "grsecurity configured for virtualisation but no virtualisation software specified"; - } - ]; - - security.grsecurity.kernelPatch = lib.mkDefault pkgs.kernelPatches.grsecurity_latest; - - systemd.services.grsec-lock = mkIf cfg.config.sysctl { - description = "grsecurity sysctl-lock Service"; - wants = [ "systemd-sysctl.service" ]; - after = [ "systemd-sysctl.service" ]; - wantedBy = [ "multi-user.target" ]; - serviceConfig.Type = "oneshot"; - serviceConfig.RemainAfterExit = "yes"; - unitConfig.ConditionPathIsReadWrite = "/proc/sys/kernel/grsecurity/grsec_lock"; - script = '' - locked=`cat /proc/sys/kernel/grsecurity/grsec_lock` - if [ "$locked" == "0" ]; then - echo 1 > /proc/sys/kernel/grsecurity/grsec_lock - echo grsecurity sysctl lock - enabled - else - echo grsecurity sysctl lock already enabled - doing nothing - fi - ''; + # Configure system tunables + boot.kernel.sysctl = { + # Removed under grsecurity + "kernel.kptr_restrict" = mkForce null; + } // optionalAttrs config.nix.useSandbox { + # chroot(2) restrictions that conflict with sandboxed Nix builds + "kernel.grsecurity.chroot_caps" = mkForce 0; + "kernel.grsecurity.chroot_deny_chroot" = mkForce 0; + "kernel.grsecurity.chroot_deny_mount" = mkForce 0; + "kernel.grsecurity.chroot_deny_pivot" = mkForce 0; + } // optionalAttrs config.boot.enableContainers { + # chroot(2) restrictions that conflict with NixOS lightweight containers + "kernel.grsecurity.chroot_deny_chmod" = mkForce 0; + "kernel.grsecurity.chroot_deny_mount" = mkForce 0; + "kernel.grsecurity.chroot_restrict_nice" = mkForce 0; }; -# systemd.services.grsec-learn = { -# description = "grsecurity learning Service"; -# wantedBy = [ "local-fs.target" ]; -# serviceConfig = { -# Type = "oneshot"; -# RemainAfterExit = "yes"; -# ExecStart = "${pkgs.gradm}/sbin/gradm -VFL /etc/grsec/learning.logs"; -# ExecStop = "${pkgs.gradm}/sbin/gradm -D"; -# }; -# }; - - system.activationScripts = lib.optionalAttrs (!cfg.config.disableRBAC) { grsec = '' - mkdir -p /etc/grsec - if [ ! -f /etc/grsec/learn_config ]; then - cp ${pkgs.gradm}/etc/grsec/learn_config /etc/grsec - fi - if [ ! -f /etc/grsec/policy ]; then - cp ${pkgs.gradm}/etc/grsec/policy /etc/grsec - fi - chmod -R 0600 /etc/grsec - ''; }; + assertions = [ + { assertion = !zfsNeededForBoot; + message = "grsecurity is currently incompatible with ZFS"; + } + ]; - # Enable AppArmor, gradm udev rules, and utilities - security.apparmor.enable = true; - boot.kernelPackages = customGrsecPkg; - services.udev.packages = lib.optional (!cfg.config.disableRBAC) pkgs.gradm; - environment.systemPackages = [ pkgs.paxctl pkgs.pax-utils ] ++ lib.optional (!cfg.config.disableRBAC) pkgs.gradm; }; } diff --git a/nixos/tests/grsecurity.nix b/nixos/tests/grsecurity.nix index 14f1aa9ff885..aadbfd8371ff 100644 --- a/nixos/tests/grsecurity.nix +++ b/nixos/tests/grsecurity.nix @@ -3,17 +3,39 @@ import ./make-test.nix ({ pkgs, ...} : { name = "grsecurity"; meta = with pkgs.stdenv.lib.maintainers; { - maintainers = [ copumpkin ]; + maintainers = [ copumpkin joachifm ]; }; machine = { config, pkgs, ... }: - { boot.kernelPackages = pkgs.linuxPackages_grsec_testing_server; }; + { security.grsecurity.enable = true; + boot.kernel.sysctl."kernel.grsecurity.deter_bruteforce" = 0; + security.apparmor.enable = true; + }; - testScript = - '' - $machine->succeed("uname -a") =~ /grsec/; - # FIXME: this seems to hang the whole test. Unclear why, but let's fix it - # $machine->succeed("${pkgs.paxtest}/bin/paxtest blackhat"); - ''; -}) + testScript = '' + subtest "grsec-lock", sub { + $machine->succeed("systemctl is-active grsec-lock"); + $machine->succeed("grep -Fq 1 /proc/sys/kernel/grsecurity/grsec_lock"); + $machine->fail("echo -n 0 >/proc/sys/kernel/grsecurity/grsec_lock"); + }; + + subtest "paxtest", sub { + # TODO: running paxtest blackhat hangs the vm + $machine->succeed("${pkgs.paxtest}/lib/paxtest/anonmap") =~ /Killed/ or die; + $machine->succeed("${pkgs.paxtest}/lib/paxtest/execbss") =~ /Killed/ or die; + $machine->succeed("${pkgs.paxtest}/lib/paxtest/execdata") =~ /Killed/ or die; + $machine->succeed("${pkgs.paxtest}/lib/paxtest/execheap") =~ /Killed/ or die; + $machine->succeed("${pkgs.paxtest}/lib/paxtest/execstack") =~ /Killed/ or die; + $machine->succeed("${pkgs.paxtest}/lib/paxtest/mprotanon") =~ /Killed/ or die; + $machine->succeed("${pkgs.paxtest}/lib/paxtest/mprotbss") =~ /Killed/ or die; + $machine->succeed("${pkgs.paxtest}/lib/paxtest/mprotdata") =~ /Killed/ or die; + $machine->succeed("${pkgs.paxtest}/lib/paxtest/mprotheap") =~ /Killed/ or die; + $machine->succeed("${pkgs.paxtest}/lib/paxtest/mprotstack") =~ /Killed/ or die; + }; + subtest "tcc", sub { + $machine->execute("echo -e '#include <stdio.h>\nint main(void) { puts(\"hello\"); return 0; }' >main.c"); + $machine->succeed("${pkgs.tinycc.bin}/bin/tcc -run main.c"); + }; + ''; +}) |