1{ config, pkgs, lib, ... }:
2
3with lib;
4
5let
6 cfg = config.security.grsecurity;
7 grsecLockPath = "/proc/sys/kernel/grsecurity/grsec_lock";
8
9 # Ascertain whether NixOS container support is required
10 containerSupportRequired =
11 config.boot.enableContainers && config.containers != {};
12in
13
14{
15 meta = {
16 maintainers = with maintainers; [ ];
17 doc = ./grsecurity.xml;
18 };
19
20 options.security.grsecurity = {
21
22 enable = mkOption {
23 type = types.bool;
24 default = false;
25 description = ''
26 Enable grsecurity/PaX.
27 '';
28 };
29
30 lockTunables = mkOption {
31 type = types.bool;
32 default = true;
33 description = ''
34 Whether to automatically lock grsecurity tunables
35 (<option>boot.kernel.sysctl."kernel.grsecurity.*"</option>). Disable
36 this to allow runtime configuration of grsecurity features. Activate
37 the <literal>grsec-lock</literal> service unit to prevent further
38 configuration until the next reboot.
39 '';
40 };
41
42 disableEfiRuntimeServices = mkOption {
43 type = types.bool;
44 default = true;
45 description = ''
46 Whether to disable access to EFI runtime services. Enabling EFI runtime
47 services creates a venue for code injection attacks on the kernel and
48 should be disabled if at all possible. Changing this option enters into
49 effect upon reboot.
50 '';
51 };
52
53 };
54
55 config = mkIf cfg.enable {
56
57 boot.kernelPackages = mkForce pkgs.linuxPackages_grsec_nixos;
58
59 boot.kernelParams = [ "grsec_sysfs_restrict=0" ]
60 ++ optional cfg.disableEfiRuntimeServices "noefi";
61
62 nixpkgs.config.grsecurity = true;
63
64 # Install PaX related utillities into the system profile.
65 environment.systemPackages = with pkgs; [ gradm paxctl pax-utils ];
66
67 # Install rules for the grsec device node
68 services.udev.packages = [ pkgs.gradm ];
69
70 # This service unit is responsible for locking the grsecurity tunables. The
71 # unit is always defined, but only activated on bootup if lockTunables is
72 # toggled. When lockTunables is toggled, failure to activate the unit will
73 # enter emergency mode. The intent is to make it difficult to silently
74 # enter multi-user mode without having locked the tunables. Some effort is
75 # made to ensure that starting the unit is an idempotent operation.
76 systemd.services.grsec-lock = {
77 description = "Lock grsecurity tunables";
78
79 wantedBy = optional cfg.lockTunables "multi-user.target";
80
81 wants = [ "local-fs.target" "systemd-sysctl.service" ];
82 after = [ "local-fs.target" "systemd-sysctl.service" ];
83 conflicts = [ "shutdown.target" ];
84
85 restartIfChanged = false;
86
87 script = ''
88 if ${pkgs.gnugrep}/bin/grep -Fq 0 ${grsecLockPath} ; then
89 echo -n 1 > ${grsecLockPath}
90 fi
91 '';
92
93 unitConfig = {
94 ConditionPathIsReadWrite = grsecLockPath;
95 DefaultDependencies = false;
96 } // optionalAttrs cfg.lockTunables {
97 OnFailure = "emergency.target";
98 };
99
100 serviceConfig = {
101 Type = "oneshot";
102 RemainAfterExit = true;
103 };
104 };
105
106 # Configure system tunables
107 boot.kernel.sysctl = {
108 # Read-only under grsecurity
109 "kernel.kptr_restrict" = mkForce null;
110
111 # All grsec tunables default to off, those not enabled below are
112 # *disabled*. We use mkDefault to allow expert users to override
113 # our choices, but use mkForce where tunables would outright
114 # conflict with other settings.
115
116 # Enable all chroot restrictions by default (overwritten as
117 # necessary below)
118 "kernel.grsecurity.chroot_caps" = mkDefault 1;
119 "kernel.grsecurity.chroot_deny_bad_rename" = mkDefault 1;
120 "kernel.grsecurity.chroot_deny_chmod" = mkDefault 1;
121 "kernel.grsecurity.chroot_deny_chroot" = mkDefault 1;
122 "kernel.grsecurity.chroot_deny_fchdir" = mkDefault 1;
123 "kernel.grsecurity.chroot_deny_mknod" = mkDefault 1;
124 "kernel.grsecurity.chroot_deny_mount" = mkDefault 1;
125 "kernel.grsecurity.chroot_deny_pivot" = mkDefault 1;
126 "kernel.grsecurity.chroot_deny_shmat" = mkDefault 1;
127 "kernel.grsecurity.chroot_deny_sysctl" = mkDefault 1;
128 "kernel.grsecurity.chroot_deny_unix" = mkDefault 1;
129 "kernel.grsecurity.chroot_enforce_chdir" = mkDefault 1;
130 "kernel.grsecurity.chroot_findtask" = mkDefault 1;
131 "kernel.grsecurity.chroot_restrict_nice" = mkDefault 1;
132
133 # Enable various grsec protections
134 "kernel.grsecurity.consistent_setxid" = mkDefault 1;
135 "kernel.grsecurity.deter_bruteforce" = mkDefault 1;
136 "kernel.grsecurity.fifo_restrictions" = mkDefault 1;
137 "kernel.grsecurity.harden_ipc" = mkDefault 1;
138 "kernel.grsecurity.harden_ptrace" = mkDefault 1;
139 "kernel.grsecurity.harden_tty" = mkDefault 1;
140 "kernel.grsecurity.ip_blackhole" = mkDefault 1;
141 "kernel.grsecurity.linking_restrictions" = mkDefault 1;
142 "kernel.grsecurity.ptrace_readexec" = mkDefault 1;
143
144 # Enable auditing
145 "kernel.grsecurity.audit_ptrace" = mkDefault 1;
146 "kernel.grsecurity.forkfail_logging" = mkDefault 1;
147 "kernel.grsecurity.rwxmap_logging" = mkDefault 1;
148 "kernel.grsecurity.signal_logging" = mkDefault 1;
149 "kernel.grsecurity.timechange_logging" = mkDefault 1;
150 } // optionalAttrs config.nix.useSandbox {
151 # chroot(2) restrictions that conflict with sandboxed Nix builds
152 "kernel.grsecurity.chroot_caps" = mkForce 0;
153 "kernel.grsecurity.chroot_deny_chmod" = mkForce 0;
154 "kernel.grsecurity.chroot_deny_chroot" = mkForce 0;
155 "kernel.grsecurity.chroot_deny_mount" = mkForce 0;
156 "kernel.grsecurity.chroot_deny_pivot" = mkForce 0;
157 } // optionalAttrs containerSupportRequired {
158 # chroot(2) restrictions that conflict with NixOS lightweight containers
159 "kernel.grsecurity.chroot_caps" = mkForce 0;
160 "kernel.grsecurity.chroot_deny_chmod" = mkForce 0;
161 "kernel.grsecurity.chroot_deny_mount" = mkForce 0;
162 "kernel.grsecurity.chroot_restrict_nice" = mkForce 0;
163 # Disable privileged IO by default, unless X is enabled
164 } // optionalAttrs (!config.services.xserver.enable) {
165 "kernel.grsecurity.disable_priv_io" = mkDefault 1;
166 };
167
168 };
169}