<commit_before>{ config, lib, pkgs, ... }:

with lib;

let
  cfg = config.security.grsecurity;

  customGrsecPkg =
    (import ../../../pkgs/build-support/grsecurity {
      grsecOptions = cfg;
      inherit pkgs lib;
    }).grsecPackage;
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.14.
        '';
      };

      testing = mkOption {
        type = types.bool;
        default = false;
        description = ''
          Enable the testing grsecurity patch, based on Linux 3.18.
        '';
      };

      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 be
            <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 be <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 be <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.
          '';
        };

        denyUSB = mkOption {
          type = types.bool;
          default = false;
          description = ''
            If true, then set <literal>GRKERNSEC_DENYUSB y</literal>.

            This enables a sysctl with name
            <literal>kernel.grsecurity.deny_new_usb</literal>. Setting
            its value to <literal>1</literal> will prevent any new USB
            devices from being recognized by the OS.  Any attempted
            USB device insertion will be logged.

            This option is intended to be used against custom USB
            devices designed to exploit vulnerabilities in various USB
            device drivers.
          '';
        };

        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.14), or the testing patch (with
            kernel 3.18) 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.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";
      unitConfig.ConditionPathIsReadWrite = "/proc/sys/kernel/grsecurity/grsec_lock";
      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   = {<commit_msg>nixos: fix grsec-lock requires<commit_after>{ config, lib, pkgs, ... }:

with lib;

let
  cfg = config.security.grsecurity;

  customGrsecPkg =
    (import ../../../pkgs/build-support/grsecurity {
      grsecOptions = cfg;
      inherit pkgs lib;
    }).grsecPackage;
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.14.
        '';
      };

      testing = mkOption {
        type = types.bool;
        default = false;
        description = ''
          Enable the testing grsecurity patch, based on Linux 3.18.
        '';
      };

      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 be
            <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 be <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 be <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.
          '';
        };

        denyUSB = mkOption {
          type = types.bool;
          default = false;
          description = ''
            If true, then set <literal>GRKERNSEC_DENYUSB y</literal>.

            This enables a sysctl with name
            <literal>kernel.grsecurity.deny_new_usb</literal>. Setting
            its value to <literal>1</literal> will prevent any new USB
            devices from being recognized by the OS.  Any attempted
            USB device insertion will be logged.

            This option is intended to be used against custom USB
            devices designed to exploit vulnerabilities in various USB
            device drivers.
          '';
        };

        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.14), or the testing patch (with
            kernel 3.18) 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.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        = [ "systemd-sysctl.service" ];
      wantedBy        = [ "multi-user.target" ];
      serviceConfig.Type = "oneshot";
      serviceConfig.RemainAfterExit = "yes";
      unitConfig.ConditionPathIsReadWrite = "/proc/sys/kernel/grsecurity/grsec_lock";
      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   = {
{'fraction_non_alphanumeric': 0.09307855259175997, 'fraction_numerical': 0.0012969607885521595, 'mean_word_length': 1.7923708353452439, 'pattern_counts': {'":': 0, '<': 155, '<?xml version=': 0, '>': 175, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4807546', 'n_tokens_mistral': 5817, 'n_tokens_neox': 5693, 'n_words': 1859}