nixpkgs/nixos/modules/security/grsecurity.nix
Joachim Fasting 43fc394a5c
grsecurity module: disable EFI runtime services by default
Enabling EFI runtime services provides a venue for injecting code into
the kernel.

When grsecurity is enabled, we close this by default by disabling access
to EFI runtime services.  The upshot of this is that
/sys/firmware/efi/efivars will be unavailable by default (and attempts
to mount it will fail).

This is not strictly a grsecurity related option, it could be made into
a general option, but it seems to be of particular interest to
grsecurity users (for non-grsecurity users, there are other, more
immediate kernel injection attack dangers to contend with anyway).
2016-08-02 10:24:49 +02:00

136 lines
4.5 KiB
Nix

{ config, pkgs, lib, ... }:
with lib;
let
cfg = config.security.grsecurity;
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) != [];
# Ascertain whether NixOS container support is required
containerSupportRequired =
config.boot.enableContainers && config.containers != {};
in
{
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 runtime configuration of grsecurity features. Activate
the <literal>grsec-lock</literal> service unit to prevent further
configuration until the next reboot.
'';
};
disableEfiRuntimeServices = mkOption {
type = types.bool;
example = false;
default = true;
description = ''
Whether to disable access to EFI runtime services. Enabling EFI runtime
services creates a venue for code injection attacks on the kernel and
should be disabled if at all possible. Changing this option enters into
effect upon reboot.
'';
};
};
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;
boot.kernelParams = optional cfg.disableEfiRuntimeServices "noefi";
system.requiredKernelConfig = with config.lib.kernelConfig;
[ (isEnabled "GRKERNSEC")
(isEnabled "PAX")
(isYES "GRKERNSEC_SYSCTL")
(isYES "GRKERNSEC_SYSCTL_DISTRO")
(isNO "GRKERNSEC_NO_RBAC")
];
# Install PaX related utillities into the system profile.
environment.systemPackages = with pkgs; [ gradm 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 = {
# Read-only 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 containerSupportRequired {
# 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";
}
];
};
}