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;
+ grsecLockPath = "/proc/sys/kernel/grsecurity/grsec_lock";
- customGrsecPkg =
- (import ../../../pkgs/build-support/grsecurity {
- grsecOptions = cfg;
- inherit pkgs lib;
- }).grsecPackage;
+ # 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
- gradm. It also includes traditional
- utilities for PaX.
- '';
- };
+ options.security.grsecurity = {
- kernelPatch = mkOption {
- type = types.attrs;
- example = lib.literalExample "pkgs.kernelPatches.grsecurity_4_1";
- description = ''
- Grsecurity patch to use.
- '';
- };
+ enable = mkEnableOption "Grsecurity/PaX";
- 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
- true 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 GRKERN_SYSCTL y. 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
- kernel.grsecurity.grsec_lock 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 GRKERN_CHROOT_CHMOD
- y. If enabled, this denies processes inside a
- chroot from setting the suid or sgid bits using
- chmod or fchmod.
-
- 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.
-
- 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 CAP_SYS_ADMIN.
-
- This protection is disabled by default because it breaks
- nixos-rebuild. Whenever possible, it is
- highly recommended to enable this protection.
- '';
- };
-
- denyUSB = mkOption {
- type = types.bool;
- default = false;
- description = ''
- If true, then set GRKERNSEC_DENYUSB y.
-
- This enables a sysctl with name
- kernel.grsecurity.deny_new_usb. Setting
- its value to 1 will prevent any new USB
- devices from being recognized by the OS. Any attempted
- USB device insertion will be logged.
-
- This option is intended to be used against custom USB
- devices designed to exploit vulnerabilities in various USB
- device drivers.
- '';
- };
-
- restrictProc = mkOption {
- type = types.bool;
- default = false;
- description = ''
- If true, then set GRKERN_PROC_USER
- y. This restricts non-root users to only viewing
- their own processes and restricts network-related
- information, kernel symbols, and module information.
- '';
- };
-
- restrictProcWithGroup = mkOption {
- type = types.bool;
- default = true;
- description = ''
- If true, then set GRKERN_PROC_USERGROUP
- y. This is similar to
- restrictProc except it allows a special
- group (specified by unrestrictProcGid)
- to still access otherwise classified information in
- /proc.
- '';
- };
-
- unrestrictProcGid = mkOption {
- type = types.int;
- default = config.ids.gids.grsecurity;
- description = ''
- If set, specifies a GID which is exempt from
- /proc restrictions (set by
- GRKERN_PROC_USERGROUP). By default,
- this is set to the GID for grsecurity,
- a predefined NixOS group, which the
- root account is a member of. You may
- conveniently add other users to this group if you need
- access to /proc
- '';
- };
-
- disableRBAC = mkOption {
- type = types.bool;
- default = false;
- description = ''
- If true, then set GRKERN_NO_RBAC
- y. This disables the
- /dev/grsec device, which in turn
- disables the RBAC system (and gradm).
- '';
- };
-
- 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.
-
- 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.
- '';
- };
-
- verboseVersion = mkOption {
- type = types.bool;
- default = false;
- description = "Use verbose version in kernel localversion.";
- };
-
- kernelExtraConfig = mkOption {
- type = types.str;
- default = "";
- description = "Extra kernel configuration parameters.";
- };
- };
- };
- };
-
- 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
+ lockTunables = mkOption {
+ type = types.bool;
+ example = false;
+ default = true;
+ description = ''
+ Whether to automatically lock grsecurity tunables
+ (). Disable
+ this to allow configuration of grsecurity features while the system is
+ running. The lock can be manually engaged by activating the
+ grsec-lock service unit.
'';
};
-# 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
- ''; };
+ config = mkIf cfg.enable {
+
+ # Allow the user to select a different package set, subject to the stated
+ # required kernel config
+ boot.kernelPackages = mkDefault pkgs.linuxPackages_grsec_nixos;
+
+ system.requiredKernelConfig = with config.lib.kernelConfig;
+ [ (isEnabled "GRKERNSEC")
+ (isEnabled "PAX")
+ (isYES "GRKERNSEC_SYSCTL")
+ (isYES "GRKERNSEC_SYSCTL_DISTRO")
+ ];
+
+ # 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" ];
+
+ # Install PaX related utillities into the system profile. Eventually, we
+ # also want to include gradm here.
+ environment.systemPackages = with pkgs; [ paxctl pax-utils ];
+
+ # Install rules for the grsec device node
+ services.udev.packages = [ pkgs.gradm ];
+
+ # 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";
+
+ wantedBy = optional cfg.lockTunables "multi-user.target";
+
+ wants = [ "local-fs.target" "systemd-sysctl.service" ];
+ after = [ "local-fs.target" "systemd-sysctl.service" ];
+ conflicts = [ "shutdown.target" ];
+
+ restartIfChanged = false;
+
+ script = ''
+ if ${pkgs.gnugrep}/bin/grep -Fq 0 ${grsecLockPath} ; then
+ echo -n 1 > ${grsecLockPath}
+ fi
+ '';
+
+ unitConfig = {
+ ConditionPathIsReadWrite = grsecLockPath;
+ DefaultDependencies = false;
+ } // optionalAttrs cfg.lockTunables {
+ OnFailure = "emergency.target";
+ };
+
+ serviceConfig = {
+ Type = "oneshot";
+ RemainAfterExit = true;
+ };
+ };
+
+ # 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;
+ };
+
+ 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;
};
}