1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
|
{ config, pkgs, ... }:
with pkgs.lib;
let
cfg = config.security.grsecurity;
mkKernel = kernel: patch:
assert patch.kversion == kernel.version;
{ inherit kernel patch;
inherit (patch) grversion revision;
};
stable-patch = with pkgs.kernelPatches;
if cfg.vserver then grsecurity_vserver else grsecurity_stable;
stableKernel = mkKernel pkgs.linux_3_2 stable-patch;
testKernel = mkKernel pkgs.linux_3_13 pkgs.kernelPatches.grsecurity_unstable;
## -- grsecurity configuration -----------------------------------------------
grsecPrioCfg =
if cfg.config.priority == "security" then
"GRKERNSEC_CONFIG_PRIORITY_SECURITY y"
else
"GRKERNSEC_CONFIG_PRIORITY_PERF y";
grsecSystemCfg =
if cfg.config.system == "desktop" then
"GRKERNSEC_CONFIG_DESKTOP y"
else
"GRKERNSEC_CONFIG_SERVER y";
grsecVirtCfg =
if cfg.config.virtualisationConfig == "none" then
"GRKERNSEC_CONFIG_VIRT_NONE y"
else if cfg.config.virtualisationConfig == "host" then
"GRKERNSEC_CONFIG_VIRT_HOST y"
else
"GRKERNSEC_CONFIG_VIRT_GUEST y";
grsecHwvirtCfg = if cfg.config.virtualisationConfig == "none" then "" else
if cfg.config.hardwareVirtualisation == true then
"GRKERNSEC_CONFIG_VIRT_EPT y"
else
"GRKERNSEC_CONFIG_VIRT_SOFT y";
grsecVirtswCfg =
let virtCfg = opt: "GRKERNSEC_CONFIG_VIRT_"+opt+" y";
in
if cfg.config.virtualisationConfig == "none" then ""
else if cfg.config.virtualisationSoftware == "xen" then virtCfg "XEN"
else if cfg.config.virtualisationSoftware == "kvm" then virtCfg "KVM"
else if cfg.config.virtualisationSoftware == "vmware" then virtCfg "VMWARE"
else virtCfg "VIRTUALBOX";
grsecMainConfig = if cfg.config.mode == "custom" then "" else ''
GRKERNSEC_CONFIG_AUTO y
${grsecPrioCfg}
${grsecSystemCfg}
${grsecVirtCfg}
${grsecHwvirtCfg}
${grsecVirtswCfg}
'';
grsecConfig =
let boolToKernOpt = b: if b then "y" else "n";
# Disable RANDSTRUCT under virtualbox, as it has some kind of
# breakage with the vbox guest drivers
randstruct = optionalString config.services.virtualbox.enable
"GRKERNSEC_RANDSTRUCT n";
# Disable restricting links under the testing kernel, as something
# has changed causing it to fail miserably during boot.
restrictLinks = optionalString cfg.testing
"GRKERNSEC_LINK n";
in ''
SECURITY_APPARMOR y
DEFAULT_SECURITY_APPARMOR y
GRKERNSEC y
${grsecMainConfig}
${if cfg.config.restrictProc then
"GRKERNSEC_PROC_USER y"
else
optionalString cfg.config.restrictProcWithGroup ''
GRKERNSEC_PROC_USERGROUP y
GRKERNSEC_PROC_GID ${toString cfg.config.unrestrictProcGid}
''
}
GRKERNSEC_SYSCTL ${boolToKernOpt cfg.config.sysctl}
GRKERNSEC_CHROOT_CHMOD ${boolToKernOpt cfg.config.denyChrootChmod}
GRKERNSEC_NO_RBAC ${boolToKernOpt cfg.config.disableRBAC}
${randstruct}
${restrictLinks}
${cfg.config.kernelExtraConfig}
'';
## -- grsecurity kernel packages ---------------------------------------------
localver = grkern:
"-grsec" + optionalString cfg.config.verboseVersion
"-${grkern.grversion}-${grkern.revision}";
grsecurityOverrider = args: grkern: {
# Apparently as of gcc 4.6, gcc-plugin headers (which are needed by PaX plugins)
# include libgmp headers, so we need these extra tweaks
buildInputs = args.buildInputs ++ [ pkgs.gmp ];
preConfigure = ''
${args.preConfigure or ""}
sed -i 's|-I|-I${pkgs.gmp}/include -I|' scripts/gcc-plugin.sh
sed -i 's|HOST_EXTRACFLAGS +=|HOST_EXTRACFLAGS += -I${pkgs.gmp}/include|' tools/gcc/Makefile
sed -i 's|HOST_EXTRACXXFLAGS +=|HOST_EXTRACXXFLAGS += -I${pkgs.gmp}/include|' tools/gcc/Makefile
rm localversion-grsec
echo ${localver grkern} > localversion-grsec
'';
};
mkGrsecPkg = grkern:
let kernelPkg = lowPrio (overrideDerivation (grkern.kernel.override (args: {
kernelPatches = args.kernelPatches ++ [ grkern.patch pkgs.kernelPatches.grsec_fix_path ];
argsOverride = {
modDirVersion = "${grkern.kernel.modDirVersion}${localver grkern}";
};
extraConfig = grsecConfig;
})) (args: grsecurityOverrider args grkern));
in pkgs.linuxPackagesFor kernelPkg (mkGrsecPkg grkern);
grsecPackage = mkGrsecPkg (if cfg.stable then stableKernel else testKernel);
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.
'';
};
stable = mkOption {
type = types.bool;
default = false;
description = ''
Enable the stable grsecurity patch, based on Linux 3.2.
'';
};
vserver = mkOption {
type = types.bool;
default = false;
description = ''
Enable the stable grsecurity/vserver patches, based on Linux 3.2.
'';
};
testing = mkOption {
type = types.bool;
default = false;
description = ''
Enable the testing grsecurity patch, based on Linux 3.13.
'';
};
config = {
mode = mkOption {
type = types.str;
default = "auto";
example = "custom";
description = ''
grsecurity configuration mode. This specifies whether
grsecurity is auto-configured or otherwise completely
manually configured. Can either by
<literal>custom</literal> or <literal>auto</literal>.
<literal>auto</literal> is recommended.
'';
};
priority = mkOption {
type = types.str;
default = "security";
example = "performance";
description = ''
grsecurity configuration priority. This specifies whether
the kernel configuration should emphasize speed or
security. Can either by <literal>security</literal> or
<literal>performance</literal>.
'';
};
system = mkOption {
type = types.str;
default = "";
example = "desktop";
description = ''
grsecurity system configuration. This specifies whether
the kernel configuration should be suitable for a Desktop
or a Server. Can either by <literal>server</literal> or
<literal>desktop</literal>.
'';
};
virtualisationConfig = mkOption {
type = types.str;
default = "none";
example = "host";
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. Can be one of <literal>none</literal>,
<literal>host</literal>, or <literal>guest</literal>.
'';
};
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.str;
default = "";
example = "kvm";
description = ''
grsecurity virtualisation software. Set this to the
specified virtual machine technology if the machine is
running as a guest, or a host.
Can be one of <literal>kvm</literal>,
<literal>xen</literal>, <literal>vmware</literal> or
<literal>virtualbox</literal>.
'';
};
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*!
If disabled, this also turns off the
<literal>systemd-sysctl</literal> service.
'';
};
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.
'';
};
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>).
'';
};
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.stable || cfg.testing;
message = ''
If grsecurity is enabled, you must select either the
stable patch (with kernel 3.2), or the testing patch (with
kernel 3.13) to continue.
'';
}
{ assertion = (cfg.stable -> !cfg.testing) || (cfg.testing -> !cfg.stable);
message = ''
You must select either the stable or testing patch, not
both.
'';
}
{ assertion = (cfg.testing -> !cfg.vserver);
message = "The vserver patches are only supported in the stable kernel.";
}
{ 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 = elem cfg.config.mode [ "auto" "custom" ];
message = "grsecurity mode must either be 'auto' or 'custom'.";
}
{ assertion = cfg.config.mode == "auto" -> elem cfg.config.system [ "desktop" "server" ];
message = "when using auto grsec mode, system must be either 'desktop' or 'server'";
}
{ assertion = cfg.config.mode == "auto" -> elem cfg.config.priority [ "performance" "security" ];
message = "when using auto grsec mode, priority must be 'performance' or 'security'.";
}
{ assertion = cfg.config.mode == "auto" -> elem cfg.config.virtualisationConfig [ "host" "guest" "none" ];
message = "when using auto grsec mode, 'virt' must be 'host', 'guest' or 'none'.";
}
{ assertion = (cfg.config.mode == "auto" && (elem cfg.config.virtualisationConfig [ "host" "guest" ])) ->
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" && (elem cfg.config.virtualisationConfig [ "host" "guest" ])) ->
elem cfg.config.virtualisationSoftware [ "kvm" "xen" "virtualbox" "vmware" ];
message = "virtualisation software must be 'kvm', 'xen', 'vmware' or 'virtualbox'";
}
];
systemd.services.grsec-lock = mkIf cfg.config.sysctl {
description = "grsecurity sysctl-lock Service";
requires = [ "sysctl.service" ];
wantedBy = [ "multi-user.target" ];
serviceConfig.Type = "oneshot";
serviceConfig.RemainAfterExit = "yes";
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
'';
};
# 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.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
'';
# Enable apparmor support, gradm udev rules, and utilities
security.apparmor.enable = true;
boot.kernelPackages = grsecPackage;
services.udev.packages = [ pkgs.gradm ];
environment.systemPackages = [ pkgs.gradm pkgs.paxctl pkgs.pax-utils ];
};
}
|