<chapter xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude" version="5.0" xml:id="sec-grsecurity"> <title>Grsecurity/PaX</title> <para> Grsecurity/PaX is a set of patches against the Linux kernel that make it harder to exploit bugs. The patchset includes protections such as enforcement of non-executable memory, address space layout randomization, and chroot jail hardening. These and other <link xlink:href="https://grsecurity.net/features.php">features</link> render entire classes of exploits inert without additional efforts on the part of the adversary. </para> <para> The NixOS grsecurity/PaX module is designed with casual users in mind and is intended to be compatible with normal desktop usage, without unnecessarily compromising security. The following sections describe the configuration and administration of a grsecurity/PaX enabled NixOS system. For more comprehensive coverage, please refer to the <link xlink:href="https://en.wikibooks.org/wiki/Grsecurity">grsecurity wikibook</link> and the <link xlink:href="https://wiki.archlinux.org/index.php/Grsecurity">Arch Linux wiki page on grsecurity</link>. <note><para>grsecurity/PaX is only available for the latest linux -stable kernel; patches against older kernels are available from upstream only for a fee.</para></note> <note><para>We standardise on a desktop oriented configuration primarily due to lack of resources. The grsecurity/PaX configuration state space is huge and each configuration requires quite a bit of testing to ensure that the resulting packages work as advertised. Defining additional package sets would likely result in a large number of functionally broken packages, to nobody's benefit.</para></note>. </para> <sect1 xml:id="sec-grsec-enable"><title>Enabling grsecurity/PaX</title> <para> To make use of grsecurity/PaX on NixOS, add the following to your <filename>configuration.nix</filename>: <programlisting> security.grsecurity.enable = true; </programlisting> followed by <programlisting> # nixos-rebuild boot # reboot </programlisting> <note><para> Enabling the grsecurity module overrides <option>boot.kernelPackages</option>, to reduce the risk of misconfiguration. <xref linkend="sec-grsec-custom-kernel" /> describes how to use a custom kernel package set. </para></note> For most users, further configuration should be unnecessary. All users are encouraged to look over <xref linkend="sec-grsec-security" /> before using the system, however. If you experience problems, please refer to <xref linkend="sec-grsec-issues" />. </para> <para> Once booted into the new system, you can optionally use <command>paxtest</command> to exercise various PaX features: <screen><![CDATA[ # nix-shell -p paxtest --command 'paxtest blackhat' Executable anonymous mapping : Killed Executable bss : Killed # ... remaining output truncated for brevity ]]></screen> </para> </sect1> <sect1 xml:id="sec-grsec-declarative-tuning"><title>Declarative tuning</title> <para> The default configuration mode is strictly declarative. Some features simply cannot be changed at all after boot, while others are locked once the system is up and running. Moreover, changes to the configuration enter into effect only upon booting into the new system. </para> <para> The NixOS module exposes a limited number of options for tuning the behavior of grsecurity/PaX. These are options thought to be of particular interest to most users. For experts, further tuning is possible via <option>boot.kernelParams</option> (see <xref linkend="sec-grsec-kernel-params" />) and <option>boot.kernel.sysctl."kernel.grsecurity.*"</option> (the wikibook contains an <link xlink:href="https://en.wikibooks.org/wiki/Grsecurity/Appendix/Sysctl_Options"> exhaustive listing of grsecurity sysctl tunables</link>). </para> </sect1> <sect1 xml:id="sec-grsec-manual-tuning"><title>Manual tuning</title> <para> To permit manual tuning of grsecurity runtime parameters, set: <programlisting> security.grsecurity.lockTunables = false; </programlisting> Once booted into this system, grsecurity features that have a corresponding sysctl tunable can be changed without rebooting, either by switching into a new system profile or via the <command>sysctl</command> utility. </para> <para> To lock all grsecurity tunables until the next boot, do: <screen> # systemctl start grsec-lock </screen> </para> </sect1> <sect1 xml:id="sec-grsec-security"><title>Security considerations</title> <para> The NixOS kernel is built using upstream's recommended settings for a desktop deployment that generally favours security over performance. This section details deviations from upstream's recommendations that may compromise operational security. <warning><para>There may be additional problems not covered here!</para> </warning>. </para> <itemizedlist> <listitem><para> The following hardening features are disabled in the NixOS kernel: <itemizedlist> <listitem><para>Kernel symbol hiding: rendered useless by redistributing kernel objects.</para></listitem> <listitem><para>Randomization of kernel structures: rendered useless by redistributing kernel objects.</para></listitem> <listitem><para>TCP simultaneous OPEN connection is permitted: breaking strict TCP conformance is inappropriate for a general purpose kernel. The trade-off is that an attacker may be able to deny outgoing connections if they are able to guess the source port allocated by your OS for that connection <emphasis>and</emphasis> also manage to initiate a TCP simultaneous OPEN on that port before the connection is actually established.</para></listitem> <listitem><para>Trusted path execution: a desirable feature, but requires some more work to operate smoothly on NixOS.</para></listitem> </itemizedlist> </para></listitem> <listitem><para> The NixOS module conditionally weakens <command>chroot</command> restrictions to accommodate NixOS lightweight containers and sandboxed Nix builds. This is problematic if the deployment also runs a privileged network facing process that <emphasis>relies</emphasis> on <command>chroot</command> for isolation. </para></listitem> <listitem><para> The NixOS kernel is patched to allow usermode helpers from anywhere in the Nix store. A usermode helper is an executable called by the kernel in certain circumstances, e.g., <command>modprobe</command>. Vanilla grsecurity only allows usermode helpers from paths typically owned by the super user. The NixOS kernel allows an attacker to inject malicious code into the Nix store which could then be executed by the kernel as a usermode helper. </para></listitem> <listitem><para> The following features are disabled because they overlap with vanilla kernel mechanisms: <itemizedlist> <listitem><para><filename class="directory">/proc</filename> hardening: use <option>security.hideProcessInformation</option> instead. This trades weaker protection for greater compatibility. </para></listitem> <listitem><para><command>dmesg</command> restrictions: use <option>boot.kernel.sysctl."kernel.dmesg_restrict"</option> instead </para></listitem> </itemizedlist> </para></listitem> </itemizedlist> </sect1> <sect1 xml:id="sec-grsec-custom-kernel"><title>Using a custom grsecurity/PaX kernel</title> <para> The NixOS kernel is likely to be either too permissive or too restrictive for many deployment scenarios. In addition to producing a kernel more suitable for a particular deployment, a custom kernel may improve security by depriving an attacker the ability to study the kernel object code, adding yet more guesswork to successfully carry out certain exploits. </para> <para> To build a custom kernel using upstream's recommended settings for server deployments, while still using the NixOS module: <programlisting> nixpkgs.config.packageOverrides = super: { linux_grsec_nixos = super.linux_grsec_nixos.override { extraConfig = '' GRKERNSEC_CONFIG_AUTO y GRKERNSEC_CONFIG_SERVER y GRKERNSEC_CONFIG_SECURITY y ''; }; } </programlisting> </para> <para> The wikibook provides an exhaustive listing of <link xlink:href="https://en.wikibooks.org/wiki/Grsecurity/Appendix/Grsecurity_and_PaX_Configuration_Options">kernel configuration options</link>. </para> <para> The NixOS module makes several assumptions about the kernel and so may be incompatible with your customised kernel. Currently, the only way to work around incompatibilities is to eschew the NixOS module. If not using the NixOS module, a custom grsecurity package set can be specified inline instead, as in <programlisting> boot.kernelPackages = let kernel = pkgs.linux_grsec_nixos.override { extraConfig = /* as above */; }; self = pkgs.linuxPackagesFor kernel self; in self; </programlisting> </para> </sect1> <sect1 xml:id="sec-grsec-pax-flags"><title>Per-executable PaX flags</title> <para> Manual tuning of per-file PaX flags for executables in the Nix store is impossible on a properly configured system. If a package in Nixpkgs fails due to PaX, that is a bug in the package recipe and should be reported to the maintainer (including relevant <command>dmesg</command> output). </para> <para> For executables installed outside of the Nix store, PaX flags can be set using the <command>paxctl</command> utility: <programlisting> paxctl -czem <replaceable>foo</replaceable> </programlisting> <warning> <para><command>paxctl</command> overwrites files in-place.</para> </warning> Equivalently, on file systems that support extended attributes: <programlisting> setfattr -n user.pax.flags -v em <replaceable>foo</replaceable> </programlisting> <!-- TODO: PaX flags via RBAC policy --> </para> </sect1> <sect1 xml:id="sec-grsec-issues"><title>Issues and work-arounds</title> <itemizedlist> <listitem><para>User namespaces require <literal>CAP_SYS_ADMIN</literal>: consequently, unprivileged namespaces are unsupported. Applications that rely on namespaces for sandboxing must use a privileged helper. For chromium there is <option>security.chromiumSuidSandbox.enable</option>.</para></listitem> <listitem><para>Access to EFI runtime services is disabled by default: this plugs a potential code injection attack vector; use <option>security.grsecurity.disableEfiRuntimeServices</option> to override this behavior.</para></listitem> <listitem><para>User initiated autoloading of modules (e.g., when using fuse or loop devices) is disallowed; either load requisite modules as root or add them to<option>boot.kernelModules</option>.</para></listitem> <listitem><para>Virtualization: KVM is the preferred virtualization solution. Xen, Virtualbox, and VMWare are <emphasis>unsupported</emphasis> and most likely require a custom kernel. </para></listitem> <listitem><para> Attaching <command>gdb</command> to a running process is disallowed by default: unprivileged users can only ptrace processes that are children of the ptracing process. To relax this restriction, set <programlisting> boot.kernel.sysctl."kernel.grsecurity.harden_ptrace" = 0; </programlisting> </para></listitem> <listitem><para> Overflows in boot critical code (e.g., the root filesystem module) can render the system unbootable. Work around by setting <programlisting> boot.kernel.kernelParams = [ "pax_size_overflow_report_only" ]; </programlisting> </para></listitem> <listitem><para> The <citerefentry><refentrytitle>modify_ldt </refentrytitle><manvolnum>2</manvolnum></citerefentry> syscall is disabled by default. This restriction can interfere with programs designed to run legacy 16-bit or segmented 32-bit code. To support applications that rely on this syscall, set <programlisting> boot.kernel.sysctl."kernel.modify_ldt" = 1; </programlisting> </para></listitem> <listitem><para> The gitlab service (<xref linkend="module-services-gitlab" />) requires a variant of the <literal>ruby</literal> interpreter built without `mprotect()` hardening, as in <programlisting> services.gitlab.packages.gitlab = pkgs.gitlab.override { ruby = pkgs.ruby.overrideAttrs (attrs: { postFixup = "paxmark m $out/bin/ruby"; }); }; </programlisting> </para></listitem> </itemizedlist> </sect1> <sect1 xml:id="sec-grsec-kernel-params"><title>Grsecurity/PaX kernel parameters</title> <para> The NixOS kernel supports the following kernel command line parameters: <itemizedlist> <listitem><para> <literal>pax_nouderef</literal>: disable UDEREF (separate kernel and user address spaces). </para></listitem> <listitem><para> <literal>pax_weakuderef</literal>: enable a faster but weaker variant of UDEREF on 64-bit processors with PCID support (check <code>grep pcid /proc/cpuinfo</code>). </para></listitem> <listitem><para> <literal>pax_sanitize_slab={off|fast|full}</literal>: control kernel slab object sanitization. Defaults to <literal>fast</literal> </para></listitem> <listitem><para> <literal>pax_size_overflow_report_only</literal>: log size overflow violations but leave the violating task running </para></listitem> <listitem><para> <literal>grsec_sysfs_restrict=[0|1]</literal>: toggle sysfs restrictions. The NixOS module sets this to <literal>0</literal> for systemd compatibility </para></listitem> </itemizedlist> </para> </sect1> </chapter>