From 75b9a7beac4529fcff9e452e5e88f6ddfb4567f6 Mon Sep 17 00:00:00 2001 From: Joachim Fasting Date: Tue, 14 Jun 2016 00:04:56 +0200 Subject: [PATCH] grsecurity: implement a single NixOS kernel This patch replaces the old grsecurity kernels with a single NixOS specific grsecurity kernel. This kernel is intended as a general purpose kernel, tuned for casual desktop use. Providing only a single kernel may seem like a regression compared to offering a multitude of flavors. It is impossible, however, to effectively test and support that many options. This is amplified by the reality that very few seem to actually use grsecurity on NixOS, meaning that bugs go unnoticed for long periods of time, simply because those code paths end up never being exercised. More generally, it is hopeless to anticipate imagined needs. It is better to start from a solid foundation and possibly add more flavours on demand. While the generic kernel is intended to cover a wide range of use cases, it cannot cover everything. For some, the configuration will be either too restrictive or too lenient. In those cases, the recommended solution is to build a custom kernel --- this is *strongly* recommended for security sensitive deployments. Building a custom grsec kernel should be as simple as ```nix linux_grsec_nixos.override { extraConfig = '' GRKERNSEC y PAX y # and so on ... ''; } ``` The generic kernel should be usable both as a KVM guest and host. When running as a host, the kernel assumes hardware virtualisation support. Virtualisation systems other than KVM are *unsupported*: users of non-KVM systems are better served by compiling a custom kernel. Unlike previous Grsecurity kernels, this configuration disables `/proc` restrictions in favor of `security.hideProcessInformation`. Known incompatibilities: - ZFS: can't load spl and zfs kernel modules; claims incompatibility with KERNEXEC method `or` and RAP; changing to `bts` does not fix the problem, which implies we'd have to disable RAP as well for ZFS to work - `kexec()`: likely incompatible with KERNEXEC (unverified) - Xen: likely incompatible with KERNEXEC and UDEREF (unverified) - Virtualbox: likely incompatible with UDEREF (unverified) --- pkgs/build-support/grsecurity/default.nix | 179 +++--------------- pkgs/build-support/grsecurity/flavors.nix | 17 -- .../linux/kernel/grsecurity-nixos-config.nix | 43 +++++ ...-4.5.patch => grsecurity-nixos-kmod.patch} | 0 ...rsecurity-4.5.nix => linux-grsecurity.nix} | 0 pkgs/os-specific/linux/kernel/patches.nix | 41 ++-- pkgs/top-level/all-packages.nix | 97 ++++------ 7 files changed, 132 insertions(+), 245 deletions(-) delete mode 100644 pkgs/build-support/grsecurity/flavors.nix create mode 100644 pkgs/os-specific/linux/kernel/grsecurity-nixos-config.nix rename pkgs/os-specific/linux/kernel/{grsecurity-path-4.5.patch => grsecurity-nixos-kmod.patch} (100%) rename pkgs/os-specific/linux/kernel/{linux-grsecurity-4.5.nix => linux-grsecurity.nix} (100%) diff --git a/pkgs/build-support/grsecurity/default.nix b/pkgs/build-support/grsecurity/default.nix index 7777b600062..8713f2d22c4 100644 --- a/pkgs/build-support/grsecurity/default.nix +++ b/pkgs/build-support/grsecurity/default.nix @@ -1,158 +1,33 @@ -{ grsecOptions, lib, pkgs }: +{ stdenv +, overrideDerivation -with lib; +# required for gcc plugins +, gmp, libmpc, mpfr -let - cfg = { - kernelPatch = grsecOptions.kernelPatch; - config = { - mode = "auto"; - sysctl = false; - denyChrootCaps = false; - denyChrootChmod = false; - denyUSB = false; - restrictProc = false; - restrictProcWithGroup = true; - unrestrictProcGid = 121; # Ugh, an awful hack. See grsecurity NixOS gid - disableRBAC = false; - disableSimultConnect = false; - redistKernel = true; - verboseVersion = false; - kernelExtraConfig = ""; - } // grsecOptions.config; - }; +# the base kernel +, kernel - vals = rec { +, grsecPatch +, kernelPatches ? [] - mkKernel = patch: - { - inherit patch; - inherit (patch) kernel patches grversion revision; - }; +, localver ? "-grsec" +, modDirVersion ? "${kernel.version}${localver}" +, extraConfig ? "" +, ... +} @ args: - grKernel = mkKernel cfg.kernelPatch; +assert (kernel.version == grsecPatch.kver); - ## -- 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 == null 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 == null 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 == null 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.virtualisation.virtualbox.guest.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 '' - GRKERNSEC y - ${grsecMainConfig} - - # Disable features rendered useless by redistributing the kernel - ${optionalString cfg.config.redistKernel '' - GRKERNSEC_RANDSTRUCT n - GRKERNSEC_HIDESYM n - ''} - - # The paxmarks mechanism relies on ELF header markings, but the default - # grsecurity configuration only enables xattr markings - PAX_PT_PAX_FLAGS y - - ${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_CAPS ${boolToKernOpt cfg.config.denyChrootCaps} - GRKERNSEC_CHROOT_CHMOD ${boolToKernOpt cfg.config.denyChrootChmod} - GRKERNSEC_DENYUSB ${boolToKernOpt cfg.config.denyUSB} - GRKERNSEC_NO_RBAC ${boolToKernOpt cfg.config.disableRBAC} - GRKERNSEC_NO_SIMULT_CONNECT ${boolToKernOpt cfg.config.disableSimultConnect} - - ${cfg.config.kernelExtraConfig} - ''; - - ## -- grsecurity kernel packages ------------------------------------------- - - localver = grkern: - "-grsec" + optionalString cfg.config.verboseVersion - "-${grkern.grversion}-${grkern.revision}"; - - grsecurityOverrider = args: grkern: { - # additional build inputs for gcc plugins, required by some PaX/grsec features - nativeBuildInputs = args.nativeBuildInputs ++ (with pkgs; [ gmp libmpc mpfr ]); - - preConfigure = (args.preConfigure or "") + '' - echo ${localver grkern} > localversion-grsec - ''; - }; - - mkGrsecKern = grkern: - lowPrio (overrideDerivation (grkern.kernel.override (args: { - kernelPatches = args.kernelPatches ++ [ grkern.patch ] ++ grkern.patches; - argsOverride = { - modDirVersion = "${grkern.kernel.modDirVersion}${localver grkern}"; - }; - extraConfig = grsecConfig; - features.grsecurity = true; - ignoreConfigErrors = true; # Too lazy to model the config options that work with grsecurity and don't for now - })) (args: grsecurityOverrider args grkern)); - - mkGrsecPkg = grkern: pkgs.linuxPackagesFor grkern (mkGrsecPkg grkern); - - ## -- Kernel packages ------------------------------------------------------ - - grsecKernel = mkGrsecKern grKernel; - grsecPackage = mkGrsecPkg grsecKernel; - }; -in vals +overrideDerivation (kernel.override { + inherit modDirVersion; + kernelPatches = [ { inherit (grsecPatch) name patch; } ] ++ kernelPatches ++ (kernel.kernelPatches or []); + features = (kernel.features or {}) // { grsecurity = true; }; + inherit extraConfig; + ignoreConfigErrors = true; +}) (attrs: { + nativeBuildInputs = [ gmp libmpc mpfr ] ++ (attrs.nativeBuildInputs or []); + preConfigure = '' + echo ${localver} >localversion-grsec + ${attrs.preConfigure or ""} + ''; +}) diff --git a/pkgs/build-support/grsecurity/flavors.nix b/pkgs/build-support/grsecurity/flavors.nix deleted file mode 100644 index 1281d60aa32..00000000000 --- a/pkgs/build-support/grsecurity/flavors.nix +++ /dev/null @@ -1,17 +0,0 @@ -let - mkOpts = prio: sys: virt: swvirt: hwvirt: - { config.priority = prio; - config.system = sys; - config.virtualisationConfig = virt; - config.hardwareVirtualisation = hwvirt; - config.virtualisationSoftware = swvirt; - }; -in -{ - desktop = - mkOpts "performance" "desktop" "host" "kvm" true; - server = - mkOpts "security" "server" "host" "kvm" true; - server_xen = - mkOpts "security" "server" "guest" "xen" true; -} diff --git a/pkgs/os-specific/linux/kernel/grsecurity-nixos-config.nix b/pkgs/os-specific/linux/kernel/grsecurity-nixos-config.nix new file mode 100644 index 00000000000..894f2d8e364 --- /dev/null +++ b/pkgs/os-specific/linux/kernel/grsecurity-nixos-config.nix @@ -0,0 +1,43 @@ +{ stdenv }: + +with stdenv.lib; + +'' +GRKERNSEC y +PAX y + +GRKERNSEC_CONFIG_AUTO y +GRKERNSEC_CONFIG_DESKTOP y +GRKERNSEC_CONFIG_VIRT_HOST y +GRKERNSEC_CONFIG_VIRT_EPT y +GRKERNSEC_CONFIG_VIRT_KVM y +GRKERNSEC_CONFIG_PRIORITY_SECURITY y + +PAX_PT_PAX_FLAGS y +PAX_XATTR_PAX_FLAGS n +PAX_EI_PAX n + +GRKERNSEC_PROC_GID 0 + +PAX_LATENT_ENTROPY n +PAX_SIZE_OVERFLOW n +GRKERNSEC_HIDESYM n +GRKERNSEC_RANDSTRUCT n +GRKERNSEC_PROC n +GRKERNSEC_SYSFS_RESTRICT n +GRKERNSEC_KMEM n +GRKERNSEC_MODHARDEN n +GRKERNSEC_NO_SIMULT_CONNECT n + +PAX_KERNEXEC_PLUGIN_METHOD_BTS y + +GRKERNSEC_ACL_HIDEKERN y +GRKERNSEC_IO y + +GRKERNSEC_AUDIT_PTRACE y +GRKERNSEC_FORKFAIL y + +GRKERNSEC_SYSCTL y +GRKERNSEC_SYSCTL_DISTRO y +GRKERNSEC_SYSCTL_ON y +'' diff --git a/pkgs/os-specific/linux/kernel/grsecurity-path-4.5.patch b/pkgs/os-specific/linux/kernel/grsecurity-nixos-kmod.patch similarity index 100% rename from pkgs/os-specific/linux/kernel/grsecurity-path-4.5.patch rename to pkgs/os-specific/linux/kernel/grsecurity-nixos-kmod.patch diff --git a/pkgs/os-specific/linux/kernel/linux-grsecurity-4.5.nix b/pkgs/os-specific/linux/kernel/linux-grsecurity.nix similarity index 100% rename from pkgs/os-specific/linux/kernel/linux-grsecurity-4.5.nix rename to pkgs/os-specific/linux/kernel/linux-grsecurity.nix diff --git a/pkgs/os-specific/linux/kernel/patches.nix b/pkgs/os-specific/linux/kernel/patches.nix index 877e51565ac..0fa9708efe5 100644 --- a/pkgs/os-specific/linux/kernel/patches.nix +++ b/pkgs/os-specific/linux/kernel/patches.nix @@ -18,20 +18,20 @@ let }; }; - grsecPatch = { grversion ? "3.1", kernel, patches, kversion, revision, branch ? "test", sha256 }: - assert kversion == kernel.version; - { name = "grsecurity-${grversion}-${kversion}"; - inherit grversion kernel patches kversion revision; + grsecPatch = { grbranch ? "test", grver ? "3.1", kver, grrev, sha256 }: rec { + name = "grsecurity-${grver}-${kver}-${grrev}"; + + # Pass these along to allow the caller to determine compatibility + inherit grver kver grrev; + + patch = fetchurl { # When updating versions/hashes, ALWAYS use the official version; we use # this mirror only because upstream removes sources files immediately upon # releasing a new version ... - patch = fetchurl { - url = "https://raw.githubusercontent.com/slashbeast/grsecurity-scrape/master/test/grsecurity-${grversion}-${kversion}-${revision}.patch"; - inherit sha256; - }; - features.grsecurity = true; + url = "https://raw.githubusercontent.com/slashbeast/grsecurity-scrape/master/${grbranch}/${name}.patch"; + inherit sha256; }; - + }; in rec { @@ -92,19 +92,18 @@ rec { grsecurity_4_4 = throw "grsecurity stable is no longer supported"; - grsecurity_4_5 = grsecPatch - { kernel = pkgs.grsecurity_base_linux_4_5; - patches = [ grsecurity_fix_path_4_5 ]; - kversion = "4.5.7"; - revision = "201606080852"; - sha256 = "1vgc314nh6bd7zw9r927lnbjq29z32g0s02jgvf635y9zz550nsh"; + grsecurity_testing = grsecPatch + { kver = "4.5.7"; + grrev = "201606080852"; + sha256 = "1vgc314nh6bd7zw9r927lnbjq29z32g0s02jgvf635y9zz550nsh"; }; - grsecurity_latest = grsecurity_4_5; - - grsecurity_fix_path_4_5 = - { name = "grsecurity-fix-path-4.5"; - patch = ./grsecurity-path-4.5.patch; + # This patch relaxes grsec constraints on the location of usermode helpers, + # e.g., modprobe, to allow calling into the Nix store. + grsecurity_nixos_kmod = + { + name = "grsecurity-nixos-kmod"; + patch = ./grsecurity-nixos-kmod.patch; }; crc_regression = diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 3bd8ca6a01d..093fcc5fb89 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -10822,32 +10822,6 @@ in linux_chromiumos_latest = self.linux_chromiumos_3_18; - # grsecurity configuration - - grsecurity_base_linux_4_5 = callPackage ../os-specific/linux/kernel/linux-grsecurity-4.5.nix { - inherit (linux_4_5) kernelPatches; - }; - - grFlavors = import ../build-support/grsecurity/flavors.nix; - - mkGrsecurity = patch: opts: - (callPackage ../build-support/grsecurity { - grsecOptions = { kernelPatch = patch; } // opts; - }); - - grKernel = patch: opts: (self.mkGrsecurity patch opts).grsecKernel; - grPackage = patch: opts: recurseIntoAttrs (self.mkGrsecurity patch opts).grsecPackage; - - # grsecurity kernels (see also linuxPackages_grsec_*) - - linux_grsec_desktop_4_5 = self.grKernel kernelPatches.grsecurity_4_5 self.grFlavors.desktop; - linux_grsec_server_4_5 = self.grKernel kernelPatches.grsecurity_4_5 self.grFlavors.server; - linux_grsec_server_xen_4_5 = self.grKernel kernelPatches.grsecurity_4_5 self.grFlavors.server_xen; - - linux_grsec_desktop_latest = self.grKernel kernelPatches.grsecurity_latest self.grFlavors.desktop; - linux_grsec_server_latest = self.grKernel kernelPatches.grsecurity_latest self.grFlavors.server; - linux_grsec_server_xen_latest = self.grKernel kernelPatches.grsecurity_latest self.grFlavors.server_xen; - /* Linux kernel modules are inherently tied to a specific kernel. So rather than provide specific instances of those packages for a specific kernel, we have a function that builds those packages @@ -10997,52 +10971,65 @@ in # Build a kernel for Xen dom0 linuxPackages_latest_xen_dom0 = recurseIntoAttrs (self.linuxPackagesFor (self.linux_latest.override { features.xen_dom0=true; }) linuxPackages_latest); - # grsecurity packages + # Grsecurity packages - linuxPackages_grsec_desktop_4_5 = self.grPackage kernelPatches.grsecurity_4_5 self.grFlavors.desktop; - linuxPackages_grsec_server_4_5 = self.grPackage kernelPatches.grsecurity_4_5 self.grFlavors.server; - linuxPackages_grsec_server_xen_4_5 = self.grPackage kernelPatches.grsecurity_4_5 self.grFlavors.server_xen; + linux_grsec_nixos = callPackage ../build-support/grsecurity { + inherit (lib) overrideDerivation; + kernel = callPackage ../os-specific/linux/kernel/linux-grsecurity.nix { + inherit (self.linux_4_5) kernelPatches; + }; + grsecPatch = self.kernelPatches.grsecurity_testing; + kernelPatches = [ self.kernelPatches.grsecurity_nixos_kmod ]; + extraConfig = callPackage ../os-specific/linux/kernel/grsecurity-nixos-config.nix { }; + }; - linuxPackages_grsec_desktop_latest = self.grPackage kernelPatches.grsecurity_latest self.grFlavors.desktop; - linuxPackages_grsec_server_latest = self.grPackage kernelPatches.grsecurity_latest self.grFlavors.server; - linuxPackages_grsec_server_xen_latest = self.grPackage kernelPatches.grsecurity_latest self.grFlavors.server_xen; + linuxPackages_grsec_nixos = + let self = linuxPackagesFor linux_grsec_nixos self; + in recurseIntoAttrs self; # grsecurity: legacy grsecurity_base_linux_3_14 = throw "grsecurity stable is no longer supported"; grsecurity_base_linux_4_4 = throw "grsecurity stable is no longer supported"; + linuxPackages_grsec_desktop_3_14 = throw "linuxPackages_grsec_desktop has been removed"; + linuxPackages_grsec_desktop_4_4 = throw "linuxPackages_grsec_desktop has been removed"; + linuxPackages_grsec_desktop_4_5 = throw "linuxPackages_grsec_desktop has been removed"; + linuxPackages_grsec_desktop_latest = throw "linuxPackages_grsec_desktop has been removed"; + + linuxPackages_grsec_server_3_14 = throw "linuxPackages_grsec_server has been removed"; + linuxPackages_grsec_server_4_4 = throw "linuxPackages_grsec_server has been removed"; + linuxPackages_grsec_server_4_5 = throw "linuxPackages_grsec_server has been removed"; + linuxPackages_grsec_server_latest = throw "linuxPackages_grsec_server has been removed"; + + linuxPackages_grsec_server_xen_3_14 = throw "linuxPackages_grsec_server_xen has been removed"; + linuxPackages_grsec_server_xen_4_4 = throw "linuxPackages_grsec_server_xen has been removed"; + linuxPackages_grsec_server_xen_4_5 = throw "linuxPackages_grsec_server_xen has been removed"; + linuxPackages_grsec_server_xen_latest = throw "linuxPackages_grsec_server_xen has been removed"; + linux_grsec_desktop_3_14 = throw "grsecurity stable is no longer supported"; - linux_grsec_server_3_14 = throw "grsecurity stable is no longer supported"; - linux_grsec_server_xen_3_14 = throw "grsecurity stable is no longer supported"; - linux_grsec_desktop_4_4 = throw "grsecurity stable is no longer supported"; - linux_grsec_server_4_4 = throw "grsecurity stable is no longer supported"; - linux_grsec_server_xen_4_4 = throw "grsecurity stable is no longer supported"; + linux_grsec_desktop_4_5 = throw "linux_grsec_desktop has been removed"; + linux_grsec_desktop_latest = throw "linux_grsec_desktop has been removed"; - linux_grsec_testing_desktop = self.linux_grsec_desktop_latest; - linux_grsec_testing_server = self.linux_grsec_server_latest; - linux_grsec_testing_server_xen = self.linux_grsec_server_xen_latest; + linux_grsec_server_3_14 = throw "grsecurity stable is no longer supported"; + linux_grsec_server_4_4 = throw "grsecurity stable is no longer supported"; + linux_grsec_server_4_5 = throw "linux_grsec_server has been removed"; + linux_grsec_server_latest = throw "linux_grsec_server_latest has been removed"; + + linux_grsec_server_xen_3_14 = throw "grsecurity stable is no longer supported"; + linux_grsec_server_xen_4_4 = throw "grsecurity stable is no longer supported"; + linux_grsec_server_xen_4_5 = throw "linux_grsec_server_xen has been removed"; + linux_grsec_server_xen_latest = throw "linux_grsec_server_xen has been removed"; linux_grsec_stable_desktop = self.linux_grsec_desktop_3_14; linux_grsec_stable_server = self.linux_grsec_server_3_14; linux_grsec_stable_server_xen = self.linux_grsec_server_xen_3_14; - linuxPackages_grsec_desktop_3_14 = self.grPackage kernelPatches.grsecurity_3_14 self.grFlavors.desktop; - linuxPackages_grsec_server_3_14 = self.grPackage kernelPatches.grsecurity_3_14 self.grFlavors.server; - linuxPackages_grsec_server_xen_3_14 = self.grPackage kernelPatches.grsecurity_3_14 self.grFlavors.server_xen; + linux_grsec_testing_desktop = self.linux_grsec_desktop_latest; + linux_grsec_testing_server = self.linux_grsec_server_latest; + linux_grsec_testing_server_xen = self.linux_grsec_server_xen_latest; - linuxPackages_grsec_desktop_4_4 = self.grPackage kernelPatches.grsecurity_4_4 self.grFlavors.desktop; - linuxPackages_grsec_server_4_4 = self.grPackage kernelPatches.grsecurity_4_4 self.grFlavors.server; - linuxPackages_grsec_server_xen_4_4 = self.grPackage kernelPatches.grsecurity_4_4 self.grFlavors.server_xen; - - linuxPackages_grsec_testing_desktop = self.linuxPackages_grsec_desktop_latest; - linuxPackages_grsec_testing_server = self.linuxPackages_grsec_server_latest; - linuxPackages_grsec_testing_server_xen = self.linuxPackages_grsec_server_xen_latest; - - linuxPackages_grsec_stable_desktop = self.linuxPackages_grsec_desktop_3_14; - linuxPackages_grsec_stable_server = self.linuxPackages_grsec_server_3_14; - linuxPackages_grsec_stable_server_xen = self.linuxPackages_grsec_server_xen_3_14; # ChromiumOS kernels linuxPackages_chromiumos_3_14 = recurseIntoAttrs (self.linuxPackagesFor self.linux_chromiumos_3_14 linuxPackages_chromiumos_3_14);