1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.security.grsecurity;
7
8 customGrsecPkg =
9 (import ../../../pkgs/build-support/grsecurity {
10 grsecOptions = cfg;
11 inherit pkgs lib;
12 }).grsecPackage;
13in
14{
15 options = {
16 security.grsecurity = {
17 enable = mkOption {
18 type = types.bool;
19 default = false;
20 description = ''
21 Enable grsecurity support. This enables advanced exploit
22 hardening for the Linux kernel, and adds support for
23 administrative Role-Based Acess Control (RBAC) via
24 <literal>gradm</literal>. It also includes traditional
25 utilities for PaX.
26 '';
27 };
28
29 stable = mkOption {
30 type = types.bool;
31 default = false;
32 description = ''
33 Enable the stable grsecurity patch, based on Linux 3.14.
34 '';
35 };
36
37 testing = mkOption {
38 type = types.bool;
39 default = false;
40 description = ''
41 Enable the testing grsecurity patch, based on Linux 4.0.
42 '';
43 };
44
45 config = {
46 mode = mkOption {
47 type = types.enum [ "auto" "custom" ];
48 default = "auto";
49 description = ''
50 grsecurity configuration mode. This specifies whether
51 grsecurity is auto-configured or otherwise completely
52 manually configured.
53 '';
54 };
55
56 priority = mkOption {
57 type = types.enum [ "security" "performance" ];
58 default = "security";
59 description = ''
60 grsecurity configuration priority. This specifies whether
61 the kernel configuration should emphasize speed or
62 security.
63 '';
64 };
65
66 system = mkOption {
67 type = types.enum [ "desktop" "server" ];
68 default = "desktop";
69 description = ''
70 grsecurity system configuration.
71 '';
72 };
73
74 virtualisationConfig = mkOption {
75 type = types.nullOr (types.enum [ "host" "guest" ]);
76 default = null;
77 description = ''
78 grsecurity virtualisation configuration. This specifies
79 the virtualisation role of the machine - that is, whether
80 it will be a virtual machine guest, a virtual machine
81 host, or neither.
82 '';
83 };
84
85 hardwareVirtualisation = mkOption {
86 type = types.nullOr types.bool;
87 default = null;
88 example = true;
89 description = ''
90 grsecurity hardware virtualisation configuration. Set to
91 <literal>true</literal> if your machine supports hardware
92 accelerated virtualisation.
93 '';
94 };
95
96 virtualisationSoftware = mkOption {
97 type = types.nullOr (types.enum [ "kvm" "xen" "vmware" "virtualbox" ]);
98 default = null;
99 description = ''
100 Configure grsecurity for use with this virtualisation software.
101 '';
102 };
103
104 sysctl = mkOption {
105 type = types.bool;
106 default = false;
107 description = ''
108 If true, then set <literal>GRKERN_SYSCTL y</literal>. If
109 enabled then grsecurity can be controlled using sysctl
110 (and turned off). You are advised to *never* enable this,
111 but if you do, make sure to always set the sysctl
112 <literal>kernel.grsecurity.grsec_lock</literal> to
113 non-zero as soon as all sysctl options are set. *THIS IS
114 EXTREMELY IMPORTANT*!
115 '';
116 };
117
118 denyChrootChmod = mkOption {
119 type = types.bool;
120 default = false;
121 description = ''
122 If true, then set <literal>GRKERN_CHROOT_CHMOD
123 y</literal>. If enabled, this denies processes inside a
124 chroot from setting the suid or sgid bits using
125 <literal>chmod</literal> or <literal>fchmod</literal>.
126
127 By default this protection is disabled - it makes it
128 impossible to use Nix to build software on your system,
129 which is what most users want.
130
131 If you are using NixOps to deploy your software to a
132 remote machine, you're encouraged to enable this as you
133 won't need to compile code.
134 '';
135 };
136
137 denyUSB = mkOption {
138 type = types.bool;
139 default = false;
140 description = ''
141 If true, then set <literal>GRKERNSEC_DENYUSB y</literal>.
142
143 This enables a sysctl with name
144 <literal>kernel.grsecurity.deny_new_usb</literal>. Setting
145 its value to <literal>1</literal> will prevent any new USB
146 devices from being recognized by the OS. Any attempted
147 USB device insertion will be logged.
148
149 This option is intended to be used against custom USB
150 devices designed to exploit vulnerabilities in various USB
151 device drivers.
152 '';
153 };
154
155 restrictProc = mkOption {
156 type = types.bool;
157 default = false;
158 description = ''
159 If true, then set <literal>GRKERN_PROC_USER
160 y</literal>. This restricts non-root users to only viewing
161 their own processes and restricts network-related
162 information, kernel symbols, and module information.
163 '';
164 };
165
166 restrictProcWithGroup = mkOption {
167 type = types.bool;
168 default = true;
169 description = ''
170 If true, then set <literal>GRKERN_PROC_USERGROUP
171 y</literal>. This is similar to
172 <literal>restrictProc</literal> except it allows a special
173 group (specified by <literal>unrestrictProcGid</literal>)
174 to still access otherwise classified information in
175 <literal>/proc</literal>.
176 '';
177 };
178
179 unrestrictProcGid = mkOption {
180 type = types.int;
181 default = config.ids.gids.grsecurity;
182 description = ''
183 If set, specifies a GID which is exempt from
184 <literal>/proc</literal> restrictions (set by
185 <literal>GRKERN_PROC_USERGROUP</literal>). By default,
186 this is set to the GID for <literal>grsecurity</literal>,
187 a predefined NixOS group, which the
188 <literal>root</literal> account is a member of. You may
189 conveniently add other users to this group if you need
190 access to <literal>/proc</literal>
191 '';
192 };
193
194 disableRBAC = mkOption {
195 type = types.bool;
196 default = false;
197 description = ''
198 If true, then set <literal>GRKERN_NO_RBAC
199 y</literal>. This disables the
200 <literal>/dev/grsec</literal> device, which in turn
201 disables the RBAC system (and <literal>gradm</literal>).
202 '';
203 };
204
205 verboseVersion = mkOption {
206 type = types.bool;
207 default = false;
208 description = "Use verbose version in kernel localversion.";
209 };
210
211 kernelExtraConfig = mkOption {
212 type = types.str;
213 default = "";
214 description = "Extra kernel configuration parameters.";
215 };
216 };
217 };
218 };
219
220 config = mkIf cfg.enable {
221 assertions =
222 [ { assertion = cfg.stable || cfg.testing;
223 message = ''
224 If grsecurity is enabled, you must select either the
225 stable patch (with kernel 3.14), or the testing patch (with
226 kernel 4.0) to continue.
227 '';
228 }
229 { assertion = !(cfg.stable && cfg.testing);
230 message = "Select either one of the stable or testing patch";
231 }
232 { assertion = (cfg.config.restrictProc -> !cfg.config.restrictProcWithGroup) ||
233 (cfg.config.restrictProcWithGroup -> !cfg.config.restrictProc);
234 message = "You cannot enable both restrictProc and restrictProcWithGroup";
235 }
236 { assertion = config.boot.kernelPackages.kernel.features ? grsecurity
237 && config.boot.kernelPackages.kernel.features.grsecurity;
238 message = "grsecurity enabled, but kernel doesn't have grsec support";
239 }
240 { assertion = (cfg.config.mode == "auto" && (cfg.config.virtualisationConfig != null)) ->
241 cfg.config.hardwareVirtualisation != null;
242 message = "when using auto grsec mode with virtualisation, you must specify if your hardware has virtualisation extensions";
243 }
244 { assertion = (cfg.config.mode == "auto" && (cfg.config.virtualisationConfig != null)) ->
245 cfg.config.virtualisationSoftware != null;
246 message = "grsecurity configured for virtualisation but no virtualisation software specified";
247 }
248 ];
249
250 systemd.services.grsec-lock = mkIf cfg.config.sysctl {
251 description = "grsecurity sysctl-lock Service";
252 requires = [ "systemd-sysctl.service" ];
253 wantedBy = [ "multi-user.target" ];
254 serviceConfig.Type = "oneshot";
255 serviceConfig.RemainAfterExit = "yes";
256 unitConfig.ConditionPathIsReadWrite = "/proc/sys/kernel/grsecurity/grsec_lock";
257 script = ''
258 locked=`cat /proc/sys/kernel/grsecurity/grsec_lock`
259 if [ "$locked" == "0" ]; then
260 echo 1 > /proc/sys/kernel/grsecurity/grsec_lock
261 echo grsecurity sysctl lock - enabled
262 else
263 echo grsecurity sysctl lock already enabled - doing nothing
264 fi
265 '';
266 };
267
268# systemd.services.grsec-learn = {
269# description = "grsecurity learning Service";
270# wantedBy = [ "local-fs.target" ];
271# serviceConfig = {
272# Type = "oneshot";
273# RemainAfterExit = "yes";
274# ExecStart = "${pkgs.gradm}/sbin/gradm -VFL /etc/grsec/learning.logs";
275# ExecStop = "${pkgs.gradm}/sbin/gradm -D";
276# };
277# };
278
279 system.activationScripts = lib.optionalAttrs (!cfg.config.disableRBAC) { grsec = ''
280 mkdir -p /etc/grsec
281 if [ ! -f /etc/grsec/learn_config ]; then
282 cp ${pkgs.gradm}/etc/grsec/learn_config /etc/grsec
283 fi
284 if [ ! -f /etc/grsec/policy ]; then
285 cp ${pkgs.gradm}/etc/grsec/policy /etc/grsec
286 fi
287 chmod -R 0600 /etc/grsec
288 ''; };
289
290 # Enable AppArmor, gradm udev rules, and utilities
291 security.apparmor.enable = true;
292 boot.kernelPackages = customGrsecPkg;
293 services.udev.packages = lib.optional (!cfg.config.disableRBAC) pkgs.gradm;
294 environment.systemPackages = [ pkgs.paxctl pkgs.pax-utils ] ++ lib.optional (!cfg.config.disableRBAC) pkgs.gradm;
295 };
296}