forked from mirrors/nixpkgs
nixos: rewrite the grsecurity module
The new module is specifically adapted to the NixOS Grsecurity/PaX kernel. The module declares the required kernel configurations and so *should* be somewhat compatible with custom Grsecurity kernels. The module exposes only a limited number of options, minimising the need for user intervention beyond enabling the module. For experts, Grsecurity/PaX behavior may be configured via `boot.kernelParams` and `boot.kernel.sysctl`. The module assumes the user knows what she's doing (esp. if she decides to modify configuration values not directly exposed by the module). Administration of Grsecurity's role based access control system is yet to be implemented.
This commit is contained in:
parent
75b9a7beac
commit
0677cc61c8
|
@ -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" ])
|
||||
|
|
|
@ -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
|
||||
<literal>gradm</literal>. 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
|
||||
<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.
|
||||
|
||||
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>.
|
||||
|
||||
This protection is disabled by default because it breaks
|
||||
<literal>nixos-rebuild</literal>. Whenever possible, it is
|
||||
highly recommended to enable this protection.
|
||||
'';
|
||||
};
|
||||
|
||||
denyUSB = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
If true, then set <literal>GRKERNSEC_DENYUSB y</literal>.
|
||||
|
||||
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.
|
||||
|
||||
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 <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.
|
||||
'';
|
||||
};
|
||||
|
||||
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>.
|
||||
'';
|
||||
};
|
||||
|
||||
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>
|
||||
'';
|
||||
};
|
||||
|
||||
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>).
|
||||
'';
|
||||
};
|
||||
|
||||
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
|
||||
(<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.
|
||||
'';
|
||||
};
|
||||
|
||||
# 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;
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue