nginx: /dev/shm/nginx is removed by something and /var/cache/nginx/ filled by something
[sourcephile-nix.git] / nixpkgs / patches / apparmor.diff
index 1514631fa34e12fa06090c676fb3be82156e4b20..5fe95b5e74265082d9f1bc338f216985fb31d01e 100644 (file)
@@ -1,8 +1,8 @@
 diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix
-index 3f60da6e7a7..4871600b5ba 100644
+index 6270ac778ae..57f3dda64cd 100644
 --- a/maintainers/maintainer-list.nix
 +++ b/maintainers/maintainer-list.nix
-@@ -4287,7 +4287,7 @@
+@@ -4779,7 +4779,7 @@
      name = "Julien Dehos";
    };
    julm = {
@@ -11,12 +11,12 @@ index 3f60da6e7a7..4871600b5ba 100644
      github = "ju1m";
      githubId = 21160136;
      name = "Julien Moutinho";
-diff --git a/nixos/doc/manual/release-notes/rl-2009.xml b/nixos/doc/manual/release-notes/rl-2009.xml
-index 782227de06f..dae2616b6ad 100644
---- a/nixos/doc/manual/release-notes/rl-2009.xml
-+++ b/nixos/doc/manual/release-notes/rl-2009.xml
-@@ -1040,6 +1040,24 @@ services.transmission.settings.rpc-bind-address = "0.0.0.0";
-      to get the previous behavior of listening on all network interfaces.
+diff --git a/nixos/doc/manual/release-notes/rl-2105.xml b/nixos/doc/manual/release-notes/rl-2105.xml
+index b7947293c01..8abee64734d 100644
+--- a/nixos/doc/manual/release-notes/rl-2105.xml
++++ b/nixos/doc/manual/release-notes/rl-2105.xml
+@@ -795,6 +795,23 @@ environment.systemPackages = [
+      The option's description was incorrect regarding ownership management and has been simplified greatly.
      </para>
     </listitem>
 +   <listitem>
@@ -31,17 +31,16 @@ index 782227de06f..dae2616b6ad 100644
 +     to provide a way to disable a profile
 +     and to select whether to confine in enforce mode (default)
 +     or in complain mode (see <literal>journalctl -b --grep apparmor</literal>).
-+     Before enabling this module, either directly
-+     or by importing <literal>&lt;nixpkgs/nixos/modules/profiles/hardened.nix&gt;</literal>,
-+     please be sure to read the documentation of <link linkend="opt-security.apparmor.enable">security.apparmor.enable</link>,
-+     and especially the part about <xref linkend="opt-security.apparmor.killUnconfinedConfinables"/>.
++     Security-minded users may also want to enable <xref linkend="opt-security.apparmor.killUnconfinedConfinables"/>,
++     at the cost of having some of their processes killed
++     when updating to a NixOS version introducing new AppArmor profiles.
 +    </para>
 +   </listitem>
     <listitem>
-     <para>
-      With this release <literal>systemd-networkd</literal> (when enabled through <xref linkend="opt-networking.useNetworkd"/>)
+      <para>
+        The GNOME desktop manager once again installs <package>gnome3.epiphany</package> by default.
 diff --git a/nixos/modules/config/fonts/fontconfig.nix b/nixos/modules/config/fonts/fontconfig.nix
-index 5b681ca5946..97607134bb1 100644
+index 6e7b8c4b88a..72827c5abaa 100644
 --- a/nixos/modules/config/fonts/fontconfig.nix
 +++ b/nixos/modules/config/fonts/fontconfig.nix
 @@ -448,6 +448,40 @@ in
@@ -86,7 +85,7 @@ index 5b681ca5946..97607134bb1 100644
      (mkIf cfg.enable {
        fonts.fontconfig.confPackages = [ confPkg ];
 diff --git a/nixos/modules/config/malloc.nix b/nixos/modules/config/malloc.nix
-index 31a659ee83f..5c5752ef515 100644
+index a3eb55d8a42..fc35993b5a8 100644
 --- a/nixos/modules/config/malloc.nix
 +++ b/nixos/modules/config/malloc.nix
 @@ -87,5 +87,12 @@ in
@@ -103,10 +102,10 @@ index 31a659ee83f..5c5752ef515 100644
    };
  }
 diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
-index cce4e8e74b4..c583e3a2593 100644
+index 4a63a09ab84..43f052d150e 100644
 --- a/nixos/modules/module-list.nix
 +++ b/nixos/modules/module-list.nix
-@@ -188,7 +188,6 @@
+@@ -201,7 +201,6 @@
    ./rename.nix
    ./security/acme.nix
    ./security/apparmor.nix
@@ -114,6 +113,18 @@ index cce4e8e74b4..c583e3a2593 100644
    ./security/audit.nix
    ./security/auditd.nix
    ./security/ca.nix
+diff --git a/nixos/modules/profiles/hardened.nix b/nixos/modules/profiles/hardened.nix
+index 00aafc6831b..3f8f78f012a 100644
+--- a/nixos/modules/profiles/hardened.nix
++++ b/nixos/modules/profiles/hardened.nix
+@@ -36,6 +36,7 @@ with lib;
+   security.virtualisation.flushL1DataCache = mkDefault "always";
+   security.apparmor.enable = mkDefault true;
++  security.apparmor.killUnconfinedConfinables = mkDefault true;
+   boot.kernelParams = [
+     # Slab/slub sanity checks, redzoning, and poisoning
 diff --git a/nixos/modules/security/apparmor-suid.nix b/nixos/modules/security/apparmor-suid.nix
 deleted file mode 100644
 index 6c479e070e2..00000000000
@@ -170,23 +181,25 @@ index 6c479e070e2..00000000000
 -
 -}
 diff --git a/nixos/modules/security/apparmor.nix b/nixos/modules/security/apparmor.nix
-index cfc65b347bc..3bf1e0fefc3 100644
+index cfc65b347bc..8683d2b487c 100644
 --- a/nixos/modules/security/apparmor.nix
 +++ b/nixos/modules/security/apparmor.nix
-@@ -1,59 +1,198 @@
+@@ -1,59 +1,214 @@
  { config, lib, pkgs, ... }:
  
++with lib;
++
  let
 -  inherit (lib) mkIf mkOption types concatMapStrings;
 +  inherit (builtins) attrNames head map match readFile;
 +  inherit (lib) types;
 +  inherit (config.environment) etc;
    cfg = config.security.apparmor;
-+  mkDisableOption = name: lib.mkEnableOption name // {
++  mkDisableOption = name: mkEnableOption name // {
 +    default = true;
 +    example = false;
 +  };
-+  enabledPolicies = lib.filterAttrs (n: p: p.enable) cfg.policies;
++  enabledPolicies = filterAttrs (n: p: p.enable) cfg.policies;
  in
  
  {
@@ -210,9 +223,8 @@ index cfc65b347bc..3bf1e0fefc3 100644
 -     };
 -   };
 +  imports = [
-+    (lib.mkRenamedOptionModule [ "security" "virtualization" "flushL1DataCache" ] [ "security" "virtualisation" "flushL1DataCache" ])
-+    (lib.mkRemovedOptionModule [ "security" "apparmor" "confineSUIDApplications" ] "Please use the new options: `security.apparmor.policies.<policy>.enable'.")
-+    (lib.mkRemovedOptionModule [ "security" "apparmor" "profiles" ] "Please use the new option: `security.apparmor.policies'.")
++    (mkRemovedOptionModule [ "security" "apparmor" "confineSUIDApplications" ] "Please use the new options: `security.apparmor.policies.<policy>.enable'.")
++    (mkRemovedOptionModule [ "security" "apparmor" "profiles" ] "Please use the new option: `security.apparmor.policies'.")
 +    apparmor/includes.nix
 +    apparmor/profiles.nix
 +  ];
@@ -221,7 +233,8 @@ index cfc65b347bc..3bf1e0fefc3 100644
 -     environment.systemPackages = [ pkgs.apparmor-utils ];
 +  options = {
 +    security.apparmor = {
-+      enable = lib.mkEnableOption ''the AppArmor Mandatory Access Control system.
++      enable = mkEnableOption ''
++        the AppArmor Mandatory Access Control system.
  
 -     boot.kernelParams = [ "apparmor=1" "security=apparmor" ];
 +        If you're enabling this module on a running system,
@@ -252,17 +265,16 @@ index cfc65b347bc..3bf1e0fefc3 100644
 -       };
 -     };
 -   };
-+        Also, beware that enabling this module will by default
-+        try to kill unconfined but confinable running processes,
-+        in order to obtain a confinement matching what is declared in the NixOS configuration.
++        Also, beware that enabling this module privileges stability over security
++        by not trying to kill unconfined but newly confinable running processes by default,
++        which can happen because AppArmor can only confine new
++        or already confined processes of an executable.
 +        This will happen when upgrading to a NixOS revision
 +        introducing an AppArmor profile for the executable of a running process.
-+        This is because enabling an AppArmor profile for an executable
-+        can only confine new or already confined processes of that executable,
-+        but leaves already running processes unconfined.
-+        Set <link linkend="opt-security.apparmor.killUnconfinedConfinables">killUnconfinedConfinables</link>
-+        to <literal>false</literal> if you prefer to leave those processes running'';
-+      policies = lib.mkOption {
++
++        Enable <xref linkend="opt-security.apparmor.killUnconfinedConfinables"/>
++        if you want this service to send a </literal>SIGTERM</literal> to those running processes'';
++      policies = mkOption {
 +        description = ''
 +          AppArmor policies.
 +        '';
@@ -270,7 +282,7 @@ index cfc65b347bc..3bf1e0fefc3 100644
 +          options = {
 +            enable = mkDisableOption "loading of the profile into the kernel";
 +            enforce = mkDisableOption "enforcing of the policy or only complain in the logs";
-+            profile = lib.mkOption {
++            profile = mkOption {
 +              description = "The policy of the profile.";
 +              type = types.lines;
 +              apply = pkgs.writeText name;
@@ -279,36 +291,41 @@ index cfc65b347bc..3bf1e0fefc3 100644
 +        }));
 +        default = {};
 +      };
-+      includes = lib.mkOption {
++      includes = mkOption {
 +        type = types.attrsOf types.lines;
 +        default = {};
 +        description = ''
 +          List of paths to be added to AppArmor's searched paths
 +          when resolving <literal>include</literal> directives.
 +        '';
-+        apply = lib.mapAttrs pkgs.writeText;
++        apply = mapAttrs pkgs.writeText;
 +      };
-+      packages = lib.mkOption {
++      packages = mkOption {
 +        type = types.listOf types.package;
 +        default = [];
 +        description = "List of packages to be added to AppArmor's include path";
 +      };
-+      enableCache = lib.mkEnableOption ''caching of AppArmor policies
++      enableCache = mkEnableOption ''
++        caching of AppArmor policies
 +        in <literal>/var/cache/apparmor/</literal>.
 +
 +        Beware that AppArmor policies almost always contain Nix store paths,
 +        and thus produce at each change of these paths
 +        a new cached version accumulating in the cache'';
-+      killUnconfinedConfinables = mkDisableOption ''killing of processes
-+        which have an AppArmor profile enabled
-+        (in <link linkend="opt-security.apparmor.policies">policies</link>)
++      killUnconfinedConfinables = mkEnableOption ''
++        killing of processes which have an AppArmor profile enabled
++        (in <xref linkend="opt-security.apparmor.policies"/>)
 +        but are not confined (because AppArmor can only confine new processes).
++
++        This is only sending a gracious <literal>SIGTERM</literal> signal to the processes,
++        not a <literal>SIGKILL</literal>.
++
 +        Beware that due to a current limitation of AppArmor,
 +        only profiles with exact paths (and no name) can enable such kills'';
 +    };
 +  };
 +
-+  config = lib.mkIf cfg.enable {
++  config = mkIf cfg.enable {
 +    assertions = map (policy:
 +      { assertion = match ".*/.*" policy == null;
 +        message = "`security.apparmor.policies.\"${policy}\"' must not contain a slash.";
@@ -317,51 +334,61 @@ index cfc65b347bc..3bf1e0fefc3 100644
 +      }
 +    ) (attrNames cfg.policies);
 +
-+    environment.systemPackages = [ pkgs.apparmor-utils ];
++    environment.systemPackages = [
++      pkgs.apparmor-utils
++      pkgs.apparmor-bin-utils
++    ];
 +    environment.etc."apparmor.d".source = pkgs.linkFarm "apparmor.d" (
 +      # It's important to put only enabledPolicies here and not all cfg.policies
 +      # because aa-remove-unknown reads profiles from all /etc/apparmor.d/*
-+      lib.mapAttrsToList (name: p: {inherit name; path=p.profile;}) enabledPolicies ++
-+      lib.mapAttrsToList (name: path: {inherit name path;}) cfg.includes
++      mapAttrsToList (name: p: { inherit name; path = p.profile; }) enabledPolicies ++
++      mapAttrsToList (name: path: { inherit name path; }) cfg.includes
 +    );
 +    environment.etc."apparmor/parser.conf".text = ''
-+      ${if cfg.enableCache then "write-cache" else "skip-cache"}
-+      cache-loc /var/cache/apparmor
-+      Include /etc/apparmor.d
-+    '' +
-+    lib.concatMapStrings (p: "Include ${p}/etc/apparmor.d\n") cfg.packages;
++        ${if cfg.enableCache then "write-cache" else "skip-cache"}
++        cache-loc /var/cache/apparmor
++        Include /etc/apparmor.d
++      '' +
++      concatMapStrings (p: "Include ${p}/etc/apparmor.d\n") cfg.packages;
 +    # For aa-logprof
 +    environment.etc."apparmor/apparmor.conf".text = ''
 +    '';
 +    # For aa-logprof
 +    environment.etc."apparmor/severity.db".source = pkgs.apparmor-utils + "/etc/apparmor/severity.db";
-+    environment.etc."apparmor/logprof.conf".text = ''
-+      [settings]
-+        # /etc/apparmor.d/ is read-only on NixOS
-+        profiledir = /var/cache/apparmor/logprof
-+        inactive_profiledir = /etc/apparmor.d/disable
-+        # Use: journalctl -b --since today --grep audit: | aa-logprof
-+        logfiles = /dev/stdin
++    environment.etc."apparmor/logprof.conf".source = pkgs.runCommand "logprof.conf" {
++      header = ''
++        [settings]
++          # /etc/apparmor.d/ is read-only on NixOS
++          profiledir = /var/cache/apparmor/logprof
++          inactive_profiledir = /etc/apparmor.d/disable
++          # Use: journalctl -b --since today --grep audit: | aa-logprof
++          logfiles = /dev/stdin
 +
-+        parser = ${pkgs.apparmor-parser}/bin/apparmor_parser
-+        ldd = ${pkgs.glibc.bin}/bin/ldd
-+        logger = ${pkgs.utillinux}/bin/logger
++          parser = ${pkgs.apparmor-parser}/bin/apparmor_parser
++          ldd = ${pkgs.glibc.bin}/bin/ldd
++          logger = ${pkgs.utillinux}/bin/logger
 +
-+        # customize how file ownership permissions are presented
-+        # 0 - off
-+        # 1 - default of what ever mode the log reported
-+        # 2 - force the new permissions to be user
-+        # 3 - force all perms on the rule to be user
-+        default_owner_prompt = 1
++          # customize how file ownership permissions are presented
++          # 0 - off
++          # 1 - default of what ever mode the log reported
++          # 2 - force the new permissions to be user
++          # 3 - force all perms on the rule to be user
++          default_owner_prompt = 1
 +
-+        custom_includes = /etc/apparmor.d ${lib.concatMapStringsSep " " (p: "${p}/etc/apparmor.d") cfg.packages}
++          custom_includes = /etc/apparmor.d ${concatMapStringsSep " " (p: "${p}/etc/apparmor.d") cfg.packages}
 +
-+      [qualifiers]
-+        ${pkgs.runtimeShell} = icnu
-+        ${pkgs.bashInteractive}/bin/sh = icnu
-+        ${pkgs.bashInteractive}/bin/bash = icnu
-+    '' + head (match "^.*\\[qualifiers](.*)" # Drop the original [settings] section.
-+                     (readFile "${pkgs.apparmor-utils}/etc/apparmor/logprof.conf"));
++        [qualifiers]
++          ${pkgs.runtimeShell} = icnu
++          ${pkgs.bashInteractive}/bin/sh = icnu
++          ${pkgs.bashInteractive}/bin/bash = icnu
++          ${config.users.defaultUserShell} = icnu
++      '';
++      footer = "${pkgs.apparmor-utils}/etc/apparmor/logprof.conf";
++      passAsFile = [ "header" ];
++    } ''
++      cp $headerPath $out
++      sed '1,/\[qualifiers\]/d' $footer >> $out
++    '';
 +
 +    boot.kernelParams = [ "apparmor=1" "security=apparmor" ];
 +
@@ -387,22 +414,22 @@ index cfc65b347bc..3bf1e0fefc3 100644
 +      serviceConfig = let
 +        killUnconfinedConfinables = pkgs.writeShellScript "apparmor-kill" ''
 +          set -eu
-+          ${pkgs.apparmor-utils}/bin/aa-status --json |
++          ${pkgs.apparmor-bin-utils}/bin/aa-status --json |
 +          ${pkgs.jq}/bin/jq --raw-output '.processes | .[] | .[] | select (.status == "unconfined") | .pid' |
 +          xargs --verbose --no-run-if-empty --delimiter='\n' \
 +          kill
 +        '';
-+        commonOpts = p: "--verbose --show-cache ${lib.optionalString (!p.enforce) "--complain "}${p.profile}";
++        commonOpts = p: "--verbose --show-cache ${optionalString (!p.enforce) "--complain "}${p.profile}";
 +        in {
 +        Type = "oneshot";
 +        RemainAfterExit = "yes";
 +        ExecStartPre = "${pkgs.apparmor-utils}/bin/aa-teardown";
-+        ExecStart = lib.mapAttrsToList (n: p: "${pkgs.apparmor-parser}/bin/apparmor_parser --add ${commonOpts p}") enabledPolicies;
-+        ExecStartPost = lib.optional cfg.killUnconfinedConfinables killUnconfinedConfinables;
++        ExecStart = mapAttrsToList (n: p: "${pkgs.apparmor-parser}/bin/apparmor_parser --add ${commonOpts p}") enabledPolicies;
++        ExecStartPost = optional cfg.killUnconfinedConfinables killUnconfinedConfinables;
 +        ExecReload =
 +          # Add or replace into the kernel profiles in enabledPolicies
 +          # (because AppArmor can do that without stopping the processes already confined).
-+          lib.mapAttrsToList (n: p: "${pkgs.apparmor-parser}/bin/apparmor_parser --replace ${commonOpts p}") enabledPolicies ++
++          mapAttrsToList (n: p: "${pkgs.apparmor-parser}/bin/apparmor_parser --replace ${commonOpts p}") enabledPolicies ++
 +          # Remove from the kernel any profile whose name is not
 +          # one of the names within the content of the profiles in enabledPolicies
 +          # (indirectly read from /etc/apparmor.d/*, without recursing into sub-directory).
@@ -410,7 +437,7 @@ index cfc65b347bc..3bf1e0fefc3 100644
 +          [ "${pkgs.apparmor-utils}/bin/aa-remove-unknown" ] ++
 +          # Optionaly kill the processes which are unconfined but now have a profile loaded
 +          # (because AppArmor can only start to confine new processes).
-+          lib.optional cfg.killUnconfinedConfinables killUnconfinedConfinables;
++          optional cfg.killUnconfinedConfinables killUnconfinedConfinables;
 +        ExecStop = "${pkgs.apparmor-utils}/bin/aa-teardown";
 +        CacheDirectory = [ "apparmor" "apparmor/logprof" ];
 +        CacheDirectoryMode = "0700";
@@ -418,26 +445,28 @@ index cfc65b347bc..3bf1e0fefc3 100644
 +    };
 +  };
 +
-+  meta.maintainers = with lib.maintainers; [ julm ];
++  meta.maintainers = with maintainers; [ julm ];
  }
 diff --git a/nixos/modules/security/apparmor/includes.nix b/nixos/modules/security/apparmor/includes.nix
 new file mode 100644
-index 00000000000..498d7e77650
+index 00000000000..e3dd410b3bb
 --- /dev/null
 +++ b/nixos/modules/security/apparmor/includes.nix
-@@ -0,0 +1,301 @@
+@@ -0,0 +1,317 @@
 +{ config, lib, pkgs, ... }:
 +let
 +  inherit (builtins) attrNames hasAttr isAttrs;
 +  inherit (lib) getLib;
 +  inherit (config.environment) etc;
++  # Utility to generate an AppArmor rule
++  # only when the given path exists in config.environment.etc
 +  etcRule = arg:
-+    let go = {path ? null, mode ? "r", trail ? ""}:
++    let go = { path ? null, mode ? "r", trail ? "" }:
 +      lib.optionalString (hasAttr path etc)
 +        "${mode} ${config.environment.etc.${path}.source}${trail},";
 +    in if isAttrs arg
 +    then go arg
-+    else go {path=arg;};
++    else go { path = arg; };
 +in
 +{
 +# FIXME: most of the etcRule calls below have been
@@ -457,76 +486,80 @@ index 00000000000..498d7e77650
 +  '';
 +  "abstractions/audio" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/audio"
-+    ${etcRule "asound.conf"}
-+    ${etcRule "esound/esd.conf"}
-+    ${etcRule "libao.conf"}
-+    ${etcRule {path="pulse"; trail="/";}}
-+    ${etcRule {path="pulse"; trail="/**";}}
-+    ${etcRule {path="sound"; trail="/";}}
-+    ${etcRule {path="sound"; trail="/**";}}
-+    ${etcRule {path="alsa/conf.d"; trail="/";}}
-+    ${etcRule {path="alsa/conf.d"; trail="/*";}}
-+    ${etcRule "openal/alsoft.conf"}
-+    ${etcRule "wildmidi/wildmidi.conf"}
-+  '';
++    '' + lib.concatMapStringsSep "\n" etcRule [
++      "asound.conf"
++      "esound/esd.conf"
++      "libao.conf"
++      { path = "pulse";  trail = "/"; }
++      { path = "pulse";  trail = "/**"; }
++      { path = "sound";  trail = "/"; }
++      { path = "sound";  trail = "/**"; }
++      { path = "alsa/conf.d";  trail = "/"; }
++      { path = "alsa/conf.d";  trail = "/*"; }
++      "openal/alsoft.conf"
++      "wildmidi/wildmidi.conf"
++    ];
 +  "abstractions/authentication" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/authentication"
 +    # Defined in security.pam
 +    include <abstractions/pam>
-+    ${etcRule "nologin"}
-+    ${etcRule "securetty"}
-+    ${etcRule {path="security"; trail="/*";}}
-+    ${etcRule "shadow"}
-+    ${etcRule "gshadow"}
-+    ${etcRule "pwdb.conf"}
-+    ${etcRule "default/passwd"}
-+    ${etcRule "login.defs"}
-+  '';
++    '' + lib.concatMapStringsSep "\n" etcRule [
++      "nologin"
++      "securetty"
++      { path = "security";  trail = "/*"; }
++      "shadow"
++      "gshadow"
++      "pwdb.conf"
++      "default/passwd"
++      "login.defs"
++    ];
 +  "abstractions/base" = ''
-+     include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/base"
-+     r ${pkgs.stdenv.cc.libc}/share/locale/**,
-+     r ${pkgs.stdenv.cc.libc}/share/locale.alias,
-+     ${lib.optionalString (pkgs.glibcLocales != null) "r ${pkgs.glibcLocales}/lib/locale/locale-archive,"}
-+     ${etcRule "localtime"}
-+     r ${pkgs.tzdata}/share/zoneinfo/**,
-+     r ${pkgs.stdenv.cc.libc}/share/i18n/**,
++    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/base"
++    r ${pkgs.stdenv.cc.libc}/share/locale/**,
++    r ${pkgs.stdenv.cc.libc}/share/locale.alias,
++    ${lib.optionalString (pkgs.glibcLocales != null) "r ${pkgs.glibcLocales}/lib/locale/locale-archive,"}
++    ${etcRule "localtime"}
++    r ${pkgs.tzdata}/share/zoneinfo/**,
++    r ${pkgs.stdenv.cc.libc}/share/i18n/**,
 +  '';
 +  "abstractions/bash" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/bash"
-+    # system-wide bash configuration
-+    ${etcRule "profile.dos"}
-+    ${etcRule "profile"}
-+    ${etcRule "profile.d"}
-+    ${etcRule {path="profile.d"; trail="/*";}}
-+    ${etcRule "bashrc"}
-+    ${etcRule "bash.bashrc"}
-+    ${etcRule "bash.bashrc.local"}
-+    ${etcRule "bash_completion"}
-+    ${etcRule "bash_completion.d"}
-+    ${etcRule {path="bash_completion.d"; trail="/*";}}
-+    # bash relies on system-wide readline configuration
-+    ${etcRule "inputrc"}
++
 +    # bash inspects filesystems at startup
 +    # and /etc/mtab is linked to /proc/mounts
 +    @{PROC}/mounts
 +
-+    # run out of /etc/bash.bashrc
-+    ${etcRule "DIR_COLORS"}
++    # system-wide bash configuration
++    '' + lib.concatMapStringsSep "\n" etcRule [
++      "profile.dos"
++      "profile"
++      "profile.d"
++      { path = "profile.d";  trail = "/*"; }
++      "bashrc"
++      "bash.bashrc"
++      "bash.bashrc.local"
++      "bash_completion"
++      "bash_completion.d"
++      { path = "bash_completion.d";  trail = "/*"; }
++      # bash relies on system-wide readline configuration
++      "inputrc"
++      # run out of /etc/bash.bashrc
++      "DIR_COLORS"
++    ];
++  "abstractions/consoles" = ''
++     include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/consoles"
 +  '';
 +  "abstractions/cups-client" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/cpus-client"
 +    ${etcRule "cups/cups-client.conf"}
 +  '';
-+  "abstractions/consoles" = ''
-+     include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/consoles"
-+  '';
 +  "abstractions/dbus-session-strict" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/dbus-session-strict"
 +    ${etcRule "machine-id"}
 +  '';
 +  "abstractions/dconf" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/dconf"
-+    ${etcRule {path="dconf"; trail="/**";}}
++    ${etcRule { path = "dconf";  trail = "/**"; }}
 +  '';
 +  "abstractions/dri-common" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/dri-common"
@@ -537,62 +570,66 @@ index 00000000000..498d7e77650
 +  # those are therefore added there to this "abstractions/fonts".
 +  "abstractions/fonts" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/fonts"
-+    ${etcRule {path="fonts"; trail="/**";}}
++    ${etcRule { path = "fonts";  trail = "/**"; }}
 +  '';
 +  "abstractions/gnome" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/gnome"
-+    ${etcRule {path="gnome"; trail="/gtkrc*";}}
-+    ${etcRule {path="gtk"; trail="/*";}}
-+    ${etcRule {path="gtk-2.0"; trail="/*";}}
-+    ${etcRule {path="gtk-3.0"; trail="/*";}}
-+    ${etcRule "orbitrc"}
 +    include <abstractions/fonts>
-+    ${etcRule {path="pango"; trail="/*";}}
-+    ${etcRule {path="/etc/gnome-vfs-2.0"; trail="/modules/";}}
-+    ${etcRule {path="/etc/gnome-vfs-2.0"; trail="/modules/*";}}
-+    ${etcRule "papersize"}
-+    ${etcRule {path="cups"; trail="/lpoptions";}}
-+    ${etcRule {path="gnome"; trail="/defaults.list";}}
-+    ${etcRule {path="xdg"; trail="/{,*-}mimeapps.list";}}
-+    ${etcRule "xdg/mimeapps.list"}
-+  '';
++    '' + lib.concatMapStringsSep "\n" etcRule [
++      { path = "gnome";  trail = "/gtkrc*"; }
++      { path = "gtk";  trail = "/*"; }
++      { path = "gtk-2.0";  trail = "/*"; }
++      { path = "gtk-3.0";  trail = "/*"; }
++      "orbitrc"
++      { path = "pango";  trail = "/*"; }
++      { path = "/etc/gnome-vfs-2.0";  trail = "/modules/"; }
++      { path = "/etc/gnome-vfs-2.0";  trail = "/modules/*"; }
++      "papersize"
++      { path = "cups";  trail = "/lpoptions"; }
++      { path = "gnome";  trail = "/defaults.list"; }
++      { path = "xdg";  trail = "/{,*-}mimeapps.list"; }
++      "xdg/mimeapps.list"
++    ];
 +  "abstractions/kde" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/kde"
-+    ${etcRule {path="qt3"; trail="/kstylerc";}}
-+    ${etcRule {path="qt3"; trail="/qt_plugins_3.3rc";}}
-+    ${etcRule {path="qt3"; trail="/qtrc";}}
-+    ${etcRule "kderc"}
-+    ${etcRule {path="kde3"; trail="/*";}}
-+    ${etcRule "kde4rc"}
-+    ${etcRule {path="xdg"; trail="/kdeglobals";}}
-+    ${etcRule {path="xdg"; trail="/Trolltech.conf";}}
-+  '';
++    '' + lib.concatMapStringsSep "\n" etcRule [
++      { path = "qt3";  trail = "/kstylerc"; }
++      { path = "qt3";  trail = "/qt_plugins_3.3rc"; }
++      { path = "qt3";  trail = "/qtrc"; }
++      "kderc"
++      { path = "kde3";  trail = "/*"; }
++      "kde4rc"
++      { path = "xdg";  trail = "/kdeglobals"; }
++      { path = "xdg";  trail = "/Trolltech.conf"; }
++    ];
 +  "abstractions/kerberosclient" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/kerberosclient"
-+    ${etcRule {path="krb5.keytab"; mode="rk";}}
-+    ${etcRule "krb5.conf"}
-+    ${etcRule "krb5.conf.d"}
-+    ${etcRule {path="krb5.conf.d"; trail="/*";}}
++    '' + lib.concatMapStringsSep "\n" etcRule [
++    { path = "krb5.keytab"; mode="rk"; }
++    "krb5.conf"
++    "krb5.conf.d"
++    { path = "krb5.conf.d";  trail = "/*"; }
 +
 +    # config files found via strings on libs
-+    ${etcRule "krb.conf"}
-+    ${etcRule "krb.realms"}
-+    ${etcRule "srvtab"}
-+  '';
++    "krb.conf"
++    "krb.realms"
++    "srvtab"
++    ];
 +  "abstractions/ldapclient" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/ldapclient"
-+    ${etcRule "ldap.conf"}
-+    ${etcRule "ldap.secret"}
-+    ${etcRule {path="openldap"; trail="/*";}}
-+    ${etcRule {path="openldap"; trail="/cacerts/*";}}
-+    ${etcRule {path="sasl2"; trail="/*";}}
-+  '';
++    '' + lib.concatMapStringsSep "\n" etcRule [
++      "ldap.conf"
++      "ldap.secret"
++      { path = "openldap";  trail = "/*"; }
++      { path = "openldap";  trail = "/cacerts/*"; }
++      { path = "sasl2";  trail = "/*"; }
++    ];
 +  "abstractions/likewise" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/likewise"
 +  '';
 +  "abstractions/mdns" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/mdns"
-+     ${etcRule "nss_mdns.conf"}
++    ${etcRule "nss_mdns.conf"}
 +  '';
 +  "abstractions/nameservice" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/nameservice"
@@ -601,31 +638,31 @@ index 00000000000..498d7e77650
 +    # looking up users by name or id, groups by name or id, hosts by name
 +    # or IP, etc. These operations may be performed through files, dns,
 +    # NIS, NIS+, LDAP, hesiod, wins, etc. Allow them all here.
-+    ${etcRule "group"}
-+    ${etcRule "host.conf"}
-+    ${etcRule "hosts"}
-+    ${etcRule "nsswitch.conf"}
-+    ${etcRule "gai.conf"}
-+    ${etcRule "passwd"}
-+    ${etcRule "protocols"}
-+
-+    # libtirpc (used for NIS/YP login) needs this
-+    ${etcRule "netconfig"}
++    mr ${getLib pkgs.nss}/lib/libnss_*.so*,
++    mr ${getLib pkgs.nss}/lib64/libnss_*.so*,
++    '' + lib.concatMapStringsSep "\n" etcRule [
++      "group"
++      "host.conf"
++      "hosts"
++      "nsswitch.conf"
++      "gai.conf"
++      "passwd"
++      "protocols"
 +
-+    ${etcRule "resolv.conf"}
++      # libtirpc (used for NIS/YP login) needs this
++      "netconfig"
 +
-+    ${etcRule {path="samba"; trail="/lmhosts";}}
-+    ${etcRule "services"}
++      "resolv.conf"
 +
-+    ${etcRule "default/nss"}
++      { path = "samba";  trail = "/lmhosts"; }
++      "services"
 +
-+    # libnl-3-200 via libnss-gw-name
-+    ${etcRule {path="libnl"; trail="/classid";}}
-+    ${etcRule {path="libnl-3"; trail="/classid";}}
++      "default/nss"
 +
-+    mr ${getLib pkgs.nss}/lib/libnss_*.so*,
-+    mr ${getLib pkgs.nss}/lib64/libnss_*.so*,
-+  '';
++      # libnl-3-200 via libnss-gw-name
++      { path = "libnl";  trail = "/classid"; }
++      { path = "libnl-3";  trail = "/classid"; }
++    ];
 +  "abstractions/nis" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/nis"
 +  '';
@@ -635,7 +672,7 @@ index 00000000000..498d7e77650
 +  '';
 +  "abstractions/opencl-common" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/opencl-common"
-+    ${etcRule {path="OpenCL"; trail="/**";}}
++    ${etcRule { path = "OpenCL";  trail = "/**"; }}
 +  '';
 +  "abstractions/opencl-mesa" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/opencl-mesa"
@@ -643,68 +680,74 @@ index 00000000000..498d7e77650
 +  '';
 +  "abstractions/openssl" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/openssl"
-+    ${etcRule {path="ssl"; trail="/openssl.cnf";}}
++    ${etcRule { path = "ssl";  trail = "/openssl.cnf"; }}
 +  '';
 +  "abstractions/p11-kit" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/p11-kit"
-+    ${etcRule {path="pkcs11"; trail="/";}}
-+    ${etcRule {path="pkcs11"; trail="/pkcs11.conf";}}
-+    ${etcRule {path="pkcs11"; trail="/modules/";}}
-+    ${etcRule {path="pkcs11"; trail="/modules/*";}}
-+  '';
++    '' + lib.concatMapStringsSep "\n" etcRule [
++      { path = "pkcs11";  trail = "/"; }
++      { path = "pkcs11";  trail = "/pkcs11.conf"; }
++      { path = "pkcs11";  trail = "/modules/"; }
++      { path = "pkcs11";  trail = "/modules/*"; }
++    ];
 +  "abstractions/perl" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/perl"
-+    ${etcRule {path="perl"; trail="/**";}}
++    ${etcRule { path = "perl";  trail = "/**"; }}
 +  '';
 +  "abstractions/php" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/php"
-+    ${etcRule {path="php"; trail="/**/";}}
-+    ${etcRule {path="php5"; trail="/**/";}}
-+    ${etcRule {path="php7"; trail="/**/";}}
-+    ${etcRule {path="php"; trail="/**.ini";}}
-+    ${etcRule {path="php5"; trail="/**.ini";}}
-+    ${etcRule {path="php7"; trail="/**.ini";}}
-+  '';
++    '' + lib.concatMapStringsSep "\n" etcRule [
++      { path = "php";  trail = "/**/"; }
++      { path = "php5";  trail = "/**/"; }
++      { path = "php7";  trail = "/**/"; }
++      { path = "php";  trail = "/**.ini"; }
++      { path = "php5";  trail = "/**.ini"; }
++      { path = "php7";  trail = "/**.ini"; }
++    ];
 +  "abstractions/postfix-common" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/postfix-common"
-+    ${etcRule "mailname"}
-+    ${etcRule {path="postfix"; trail="/*.cf";}}
-+    ${etcRule "postfix/main.cf"}
-+    ${etcRule "postfix/master.cf"}
-+  '';
++    '' + lib.concatMapStringsSep "\n" etcRule [
++      "mailname"
++      { path = "postfix";  trail = "/*.cf"; }
++      "postfix/main.cf"
++      "postfix/master.cf"
++    ];
 +  "abstractions/python" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/python"
 +  '';
 +  "abstractions/qt5" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/qt5"
-+    ${etcRule {path="xdg"; trail="/QtProject/qtlogging.ini";}}
-+    ${etcRule {path="xdg/QtProject"; trail="/qtlogging.ini";}}
-+    ${etcRule "xdg/QtProject/qtlogging.ini"}
-+  '';
++    '' + lib.concatMapStringsSep "\n" etcRule [
++      { path = "xdg";  trail = "/QtProject/qtlogging.ini"; }
++      { path = "xdg/QtProject";  trail = "/qtlogging.ini"; }
++      "xdg/QtProject/qtlogging.ini"
++    ];
 +  "abstractions/samba" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/samba"
-+    ${etcRule {path="samba"; trail="/*";}}
++    ${etcRule { path = "samba";  trail = "/*"; }}
 +  '';
 +  "abstractions/ssl_certs" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/ssl_certs"
-+    ${etcRule "ssl/certs/ca-certificates.crt"}
-+    ${etcRule "ssl/certs/ca-bundle.crt"}
-+    ${etcRule "pki/tls/certs/ca-bundle.crt"}
 +
-+    ${etcRule {path="ssl/trust"; trail="/";}}
-+    ${etcRule {path="ssl/trust"; trail="/*";}}
-+    ${etcRule {path="ssl/trust/anchors"; trail="/";}}
-+    ${etcRule {path="ssl/trust/anchors"; trail="/**";}}
-+    ${etcRule {path="pki/trust"; trail="/";}}
-+    ${etcRule {path="pki/trust"; trail="/*";}}
-+    ${etcRule {path="pki/trust/anchors"; trail="/";}}
-+    ${etcRule {path="pki/trust/anchors"; trail="/**";}}
-+
-+    # security.acme NixOS module
++    # For the NixOS module: security.acme
 +    r /var/lib/acme/*/cert.pem,
 +    r /var/lib/acme/*/chain.pem,
 +    r /var/lib/acme/*/fullchain.pem,
-+  '';
++
++    '' + lib.concatMapStringsSep "\n" etcRule [
++      "ssl/certs/ca-certificates.crt"
++      "ssl/certs/ca-bundle.crt"
++      "pki/tls/certs/ca-bundle.crt"
++
++      { path = "ssl/trust";  trail = "/"; }
++      { path = "ssl/trust";  trail = "/*"; }
++      { path = "ssl/trust/anchors";  trail = "/"; }
++      { path = "ssl/trust/anchors";  trail = "/**"; }
++      { path = "pki/trust";  trail = "/"; }
++      { path = "pki/trust";  trail = "/*"; }
++      { path = "pki/trust/anchors";  trail = "/"; }
++      { path = "pki/trust/anchors";  trail = "/**"; }
++    ];
 +  "abstractions/ssl_keys" = ''
 +    # security.acme NixOS module
 +    r /var/lib/acme/*/full.pem,
@@ -712,18 +755,18 @@ index 00000000000..498d7e77650
 +  '';
 +  "abstractions/vulkan" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/vulkan"
-+    ${etcRule {path="vulkan/icd.d"; trail="/";}}
-+    ${etcRule {path="vulkan/icd.d"; trail="/*.json";}}
++    ${etcRule { path = "vulkan/icd.d";  trail = "/"; }}
++    ${etcRule { path = "vulkan/icd.d";  trail = "/*.json"; }}
 +  '';
 +  "abstractions/winbind" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/winbind"
-+    ${etcRule {path="samba"; trail="/smb.conf";}}
-+    ${etcRule {path="samba"; trail="/dhcp.conf";}}
++    ${etcRule { path = "samba";  trail = "/smb.conf"; }}
++    ${etcRule { path = "samba";  trail = "/dhcp.conf"; }}
 +  '';
 +  "abstractions/X" = ''
 +    include "${pkgs.apparmor-profiles}/etc/apparmor.d/abstractions/X"
-+    ${etcRule {path="X11/cursors"; trail="/";}}
-+    ${etcRule {path="X11/cursors"; trail="/**";}}
++    ${etcRule { path = "X11/cursors";  trail = "/"; }}
++    ${etcRule { path = "X11/cursors";  trail = "/**"; }}
 +  '';
 +};
 +}
@@ -744,82 +787,117 @@ index 00000000000..8eb630b5a48
 +  # would not work if the second one were to re-include <tunables/global>.
 +'';
 +}
+diff --git a/nixos/modules/security/misc.nix b/nixos/modules/security/misc.nix
+index d51dbbb77f7..e7abc1e0d59 100644
+--- a/nixos/modules/security/misc.nix
++++ b/nixos/modules/security/misc.nix
+@@ -7,6 +7,10 @@ with lib;
+     maintainers = [ maintainers.joachifm ];
+   };
++  imports = [
++    (lib.mkRenamedOptionModule [ "security" "virtualization" "flushL1DataCache" ] [ "security" "virtualisation" "flushL1DataCache" ])
++  ];
++
+   options = {
+     security.allowUserNamespaces = mkOption {
+       type = types.bool;
 diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix
-index a20d0a243a8..b29f51260a8 100644
+index 103cf205012..1c49131d789 100644
 --- a/nixos/modules/security/pam.nix
 +++ b/nixos/modules/security/pam.nix
-@@ -850,6 +850,61 @@ in
+@@ -895,6 +895,81 @@ in
          runuser-l = { rootOK = true; unixAuth = false; };
        };
  
 +    security.apparmor.includes."abstractions/pam" = let
 +      isEnabled = test: fold or false (map test (attrValues config.security.pam.services));
-+      in ''
-+      ${lib.concatMapStringsSep "\n"
-+         (name: "r ${config.environment.etc."pam.d/${name}".source},")
-+         (attrNames config.security.pam.services)}
++      in
++      lib.concatMapStringsSep "\n"
++        (name: "r ${config.environment.etc."pam.d/${name}".source},")
++        (attrNames config.security.pam.services) +
++      ''
 +      mr ${getLib pkgs.pam}/lib/security/pam_filter/*,
 +      mr ${getLib pkgs.pam}/lib/security/pam_*.so,
 +      r ${getLib pkgs.pam}/lib/security/,
-+      ${optionalString use_ldap
-+        "mr ${pam_ldap}/lib/security/pam_ldap.so,"}
-+      ${optionalString config.services.sssd.enable
-+        "mr ${pkgs.sssd}/lib/security/pam_sss.so,"}
-+      ${optionalString config.krb5.enable ''
++      '' +
++      optionalString use_ldap ''
++         mr ${pam_ldap}/lib/security/pam_ldap.so,
++      '' +
++      optionalString config.services.sssd.enable ''
++        mr ${pkgs.sssd}/lib/security/pam_sss.so,
++      '' +
++      optionalString config.krb5.enable ''
 +        mr ${pam_krb5}/lib/security/pam_krb5.so,
 +        mr ${pam_ccreds}/lib/security/pam_ccreds.so,
-+      ''}
-+      ${optionalString (isEnabled (cfg: cfg.googleOsLoginAccountVerification)) ''
++      '' +
++      optionalString (isEnabled (cfg: cfg.googleOsLoginAccountVerification)) ''
 +        mr ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so,
 +        mr ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_admin.so,
-+      ''}
-+      ${optionalString (isEnabled (cfg: cfg.googleOsLoginAuthentication))
-+        "mr ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so,"}
-+      ${optionalString (config.security.pam.enableSSHAgentAuth && isEnabled (cfg: cfg.sshAgentAuth))
-+        "mr ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.fprintAuth))
-+        "mr ${pkgs.fprintd}/lib/security/pam_fprintd.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.u2fAuth))
-+        "mr ${pkgs.pam_u2f}/lib/security/pam_u2f.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.usbAuth))
-+        "mr ${pkgs.pam_usb}/lib/security/pam_usb.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.oathAuth))
-+        "mr ${pkgs.oathToolkit}/lib/security/pam_oath.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.yubicoAuth))
-+        "mr ${pkgs.yubico-pam}/lib/security/pam_yubico.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.duoSecurity.enable))
-+        "mr ${pkgs.duo-unix}/lib/security/pam_duo.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.otpwAuth))
-+        "mr ${pkgs.otpw}/lib/security/pam_otpw.so,"}
-+      ${optionalString config.security.pam.enableEcryptfs
-+        "mr ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.pamMount))
-+        "mr ${pkgs.pam_mount}/lib/security/pam_mount.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.enableGnomeKeyring))
-+        "mr ${pkgs.gnome3.gnome-keyring}/lib/security/pam_gnome_keyring.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.startSession))
-+        "mr ${pkgs.systemd}/lib/security/pam_systemd.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.enableAppArmor) && config.security.apparmor.enable)
-+        "mr ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so,"}
-+      ${optionalString (isEnabled (cfg: cfg.enableKwallet))
-+        "mr ${pkgs.plasma5.kwallet-pam}/lib/security/pam_kwallet5.so,"}
-+      ${optionalString config.virtualisation.lxc.lxcfs.enable
-+        "mr ${pkgs.lxc}/lib/security/pam_cgfs.so"}
-+    '';
-+
++      '' +
++      optionalString (isEnabled (cfg: cfg.googleOsLoginAuthentication)) ''
++        mr ${pkgs.google-compute-engine-oslogin}/lib/pam_oslogin_login.so,
++      '' +
++      optionalString (config.security.pam.enableSSHAgentAuth
++                     && isEnabled (cfg: cfg.sshAgentAuth)) ''
++        mr ${pkgs.pam_ssh_agent_auth}/libexec/pam_ssh_agent_auth.so,
++      '' +
++      optionalString (isEnabled (cfg: cfg.fprintAuth)) ''
++        mr ${pkgs.fprintd}/lib/security/pam_fprintd.so,
++      '' +
++      optionalString (isEnabled (cfg: cfg.u2fAuth)) ''
++        mr ${pkgs.pam_u2f}/lib/security/pam_u2f.so,
++      '' +
++      optionalString (isEnabled (cfg: cfg.usbAuth)) ''
++        mr ${pkgs.pam_usb}/lib/security/pam_usb.so,
++      '' +
++      optionalString (isEnabled (cfg: cfg.oathAuth)) ''
++        "mr ${pkgs.oathToolkit}/lib/security/pam_oath.so,
++      '' +
++      optionalString (isEnabled (cfg: cfg.yubicoAuth)) ''
++        mr ${pkgs.yubico-pam}/lib/security/pam_yubico.so,
++      '' +
++      optionalString (isEnabled (cfg: cfg.duoSecurity.enable)) ''
++        mr ${pkgs.duo-unix}/lib/security/pam_duo.so,
++      '' +
++      optionalString (isEnabled (cfg: cfg.otpwAuth)) ''
++        mr ${pkgs.otpw}/lib/security/pam_otpw.so,
++      '' +
++      optionalString config.security.pam.enableEcryptfs ''
++        mr ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so,
++      '' +
++      optionalString (isEnabled (cfg: cfg.pamMount)) ''
++        mr ${pkgs.pam_mount}/lib/security/pam_mount.so,
++      '' +
++      optionalString (isEnabled (cfg: cfg.enableGnomeKeyring)) ''
++        mr ${pkgs.gnome3.gnome-keyring}/lib/security/pam_gnome_keyring.so,
++      '' +
++      optionalString (isEnabled (cfg: cfg.startSession)) ''
++        mr ${pkgs.systemd}/lib/security/pam_systemd.so,
++      '' +
++      optionalString (isEnabled (cfg: cfg.enableAppArmor)
++                     && config.security.apparmor.enable) ''
++        mr ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so,
++      '' +
++      optionalString (isEnabled (cfg: cfg.enableKwallet)) ''
++        mr ${pkgs.plasma5.kwallet-pam}/lib/security/pam_kwallet5.so,
++      '' +
++      optionalString config.virtualisation.lxc.lxcfs.enable ''
++        mr ${pkgs.lxc}/lib/security/pam_cgfs.so
++      '';
    };
  
  }
 diff --git a/nixos/modules/security/wrappers/default.nix b/nixos/modules/security/wrappers/default.nix
-index 52de21bca9b..f560f5c7628 100644
+index 3cbf22fea7a..1e65f451515 100644
 --- a/nixos/modules/security/wrappers/default.nix
 +++ b/nixos/modules/security/wrappers/default.nix
-@@ -179,6 +179,14 @@ in
+@@ -171,6 +171,14 @@ in
        export PATH="${wrapperDir}:$PATH"
      '';
  
 +    security.apparmor.includes."nixos/security.wrappers" = ''
-+      include "${pkgs.apparmorRulesFromClosure {} [
++      include "${pkgs.apparmorRulesFromClosure { name="security.wrappers"; } [
 +        securityWrapper
 +        pkgs.stdenv.cc.cc
 +        pkgs.stdenv.cc.libc
@@ -830,20 +908,315 @@ index 52de21bca9b..f560f5c7628 100644
      system.activationScripts.wrappers =
        lib.stringAfter [ "specialfs" "users" ]
 diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix
-index 014a22bb5a8..57982c20ccd 100644
+index 7bec073e26f..779924a65a8 100644
 --- a/nixos/modules/services/torrent/transmission.nix
 +++ b/nixos/modules/services/torrent/transmission.nix
-@@ -5,7 +5,7 @@ with lib;
+@@ -5,17 +5,22 @@ with lib;
  let
    cfg = config.services.transmission;
    inherit (config.environment) etc;
 -  apparmor = config.security.apparmor.enable;
 +  apparmor = config.security.apparmor;
    rootDir = "/run/transmission";
-   homeDir = "/var/lib/transmission";
+-  homeDir = "/var/lib/transmission";
    settingsDir = ".config/transmission-daemon";
-@@ -184,8 +184,8 @@ in
+   downloadsDir = "Downloads";
+   incompleteDir = ".incomplete";
+   watchDir = "watchdir";
+-  # TODO: switch to configGen.json once RFC0042 is implemented
+-  settingsFile = pkgs.writeText "settings.json" (builtins.toJSON cfg.settings);
++  settingsFormat = pkgs.formats.json {};
++  settingsFile = settingsFormat.generate "settings.json" cfg.settings;
+ in
+ {
++  imports = [
++    (mkRenamedOptionModule ["services" "transmission" "port"]
++                           ["services" "transmission" "settings" "rpc-port"])
++    (mkAliasOptionModule ["services" "transmission" "openFirewall"]
++                         ["services" "transmission" "openPeerPorts"])
++  ];
+   options = {
+     services.transmission = {
+       enable = mkEnableOption ''the headless Transmission BitTorrent daemon.
+@@ -24,48 +29,141 @@ in
+         transmission-remote, the WebUI (http://127.0.0.1:9091/ by default),
+         or other clients like stig or tremc.
+-        Torrents are downloaded to ${homeDir}/${downloadsDir} by default and are
++        Torrents are downloaded to <xref linkend="opt-services.transmission.home"/>/${downloadsDir} by default and are
+         accessible to users in the "transmission" group'';
+-      settings = mkOption rec {
+-        # TODO: switch to types.config.json as prescribed by RFC0042 once it's implemented
+-        type = types.attrs;
+-        apply = recursiveUpdate default;
+-        default =
+-          {
+-            download-dir = "${cfg.home}/${downloadsDir}";
+-            incomplete-dir = "${cfg.home}/${incompleteDir}";
+-            incomplete-dir-enabled = true;
+-            watch-dir = "${cfg.home}/${watchDir}";
+-            watch-dir-enabled = false;
+-            message-level = 1;
+-            peer-port = 51413;
+-            peer-port-random-high = 65535;
+-            peer-port-random-low = 49152;
+-            peer-port-random-on-start = false;
+-            rpc-bind-address = "127.0.0.1";
+-            rpc-port = 9091;
+-            script-torrent-done-enabled = false;
+-            script-torrent-done-filename = "";
+-            umask = 2; # 0o002 in decimal as expected by Transmission
+-            utp-enabled = true;
+-          };
+-        example =
+-          {
+-            download-dir = "/srv/torrents/";
+-            incomplete-dir = "/srv/torrents/.incomplete/";
+-            incomplete-dir-enabled = true;
+-            rpc-whitelist = "127.0.0.1,192.168.*.*";
+-          };
++      settings = mkOption {
+         description = ''
+-          Attribute set whose fields overwrites fields in
++          Settings whose options overwrite fields in
+           <literal>.config/transmission-daemon/settings.json</literal>
+-          (each time the service starts). String values must be quoted, integer and
+-          boolean values must not.
++          (each time the service starts).
+           See <link xlink:href="https://github.com/transmission/transmission/wiki/Editing-Configuration-Files">Transmission's Wiki</link>
+-          for documentation.
++          for documentation of settings not explicitely covered by this module.
+         '';
++        default = {};
++        type = types.submodule {
++          freeformType = settingsFormat.type;
++          options.download-dir = mkOption {
++            type = types.path;
++            default = "${cfg.home}/${downloadsDir}";
++            description = "Directory where to download torrents.";
++          };
++          options.incomplete-dir = mkOption {
++            type = types.path;
++            default = "${cfg.home}/${incompleteDir}";
++            description = ''
++              When enabled with
++              services.transmission.home
++              <xref linkend="opt-services.transmission.settings.incomplete-dir-enabled"/>,
++              new torrents will download the files to this directory.
++              When complete, the files will be moved to download-dir
++              <xref linkend="opt-services.transmission.settings.download-dir"/>.
++            '';
++          };
++          options.incomplete-dir-enabled = mkOption {
++            type = types.bool;
++            default = true;
++            description = "";
++          };
++          options.message-level = mkOption {
++            type = types.ints.between 0 2;
++            default = 2;
++            description = "Set verbosity of transmission messages.";
++          };
++          options.peer-port = mkOption {
++            type = types.port;
++            default = 51413;
++            description = "The peer port to listen for incoming connections.";
++          };
++          options.peer-port-random-high = mkOption {
++            type = types.port;
++            default = 65535;
++            description = ''
++              The maximum peer port to listen to for incoming connections
++              when <xref linkend="opt-services.transmission.settings.peer-port-random-on-start"/> is enabled.
++            '';
++          };
++          options.peer-port-random-low = mkOption {
++            type = types.port;
++            default = 65535;
++            description = ''
++              The minimal peer port to listen to for incoming connections
++              when <xref linkend="opt-services.transmission.settings.peer-port-random-on-start"/> is enabled.
++            '';
++          };
++          options.peer-port-random-on-start = mkOption {
++            type = types.bool;
++            default = false;
++            description = "Randomize the peer port.";
++          };
++          options.rpc-bind-address = mkOption {
++            type = types.str;
++            default = "127.0.0.1";
++            example = "0.0.0.0";
++            description = ''
++              Where to listen for RPC connections.
++              Use \"0.0.0.0\" to listen on all interfaces.
++            '';
++          };
++          options.rpc-port = mkOption {
++            type = types.port;
++            default = 9091;
++            description = "The RPC port to listen to.";
++          };
++          options.script-torrent-done-enabled = mkOption {
++            type = types.bool;
++            default = false;
++            description = ''
++              Whether to run
++              <xref linkend="opt-services.transmission.settings.script-torrent-done-filename"/>
++              at torrent completion.
++            '';
++          };
++          options.script-torrent-done-filename = mkOption {
++            type = types.nullOr types.path;
++            default = null;
++            description = "Executable to be run at torrent completion.";
++          };
++          options.umask = mkOption {
++            type = types.int;
++            default = 2;
++            description = ''
++              Sets transmission's file mode creation mask.
++              See the umask(2) manpage for more information.
++              Users who want their saved torrents to be world-writable
++              may want to set this value to 0.
++              Bear in mind that the json markup language only accepts numbers in base 10,
++              so the standard umask(2) octal notation "022" is written in settings.json as 18.
++            '';
++          };
++          options.utp-enabled = mkOption {
++            type = types.bool;
++            default = true;
++            description = ''
++              Whether to enable <link xlink:href="http://en.wikipedia.org/wiki/Micro_Transport_Protocol">Micro Transport Protocol (µTP)</link>.
++            '';
++          };
++          options.watch-dir = mkOption {
++            type = types.path;
++            default = "${cfg.home}/${watchDir}";
++            description = "Watch a directory for torrent files and add them to transmission.";
++          };
++          options.watch-dir-enabled = mkOption {
++            type = types.bool;
++            default = false;
++            description = ''Whether to enable the
++              <xref linkend="opt-services.transmission.settings.watch-dir"/>.
++            '';
++          };
++          options.trash-original-torrent-files = mkOption {
++            type = types.bool;
++            default = false;
++            description = ''Whether to delete torrents added from the
++              <xref linkend="opt-services.transmission.settings.watch-dir"/>.
++            '';
++          };
++        };
+       };
+       downloadDirPermissions = mkOption {
+@@ -74,31 +172,22 @@ in
+         example = "775";
+         description = ''
+           The permissions set by <literal>systemd.activationScripts.transmission-daemon</literal>
+-          on the directories <link linkend="opt-services.transmission.settings">settings.download-dir</link>
+-          and <link linkend="opt-services.transmission.settings">settings.incomplete-dir</link>.
++          on the directories <xref linkend="opt-services.transmission.settings.download-dir"/>
++          and <xref linkend="opt-services.transmission.settings.incomplete-dir"/>.
+           Note that you may also want to change
+-          <link linkend="opt-services.transmission.settings">settings.umask</link>.
+-        '';
+-      };
+-
+-      port = mkOption {
+-        type = types.port;
+-        description = ''
+-          TCP port number to run the RPC/web interface.
+-
+-          If instead you want to change the peer port,
+-          use <link linkend="opt-services.transmission.settings">settings.peer-port</link>
+-          or <link linkend="opt-services.transmission.settings">settings.peer-port-random-on-start</link>.
++          <xref linkend="opt-services.transmission.settings.umask"/>.
+         '';
+       };
+       home = mkOption {
+         type = types.path;
+-        default = homeDir;
++        default = "/var/lib/transmission";
+         description = ''
+           The directory where Transmission will create <literal>${settingsDir}</literal>.
+-          as well as <literal>${downloadsDir}/</literal> unless <link linkend="opt-services.transmission.settings">settings.download-dir</link> is changed,
+-          and <literal>${incompleteDir}/</literal> unless <link linkend="opt-services.transmission.settings">settings.incomplete-dir</link> is changed.
++          as well as <literal>${downloadsDir}/</literal> unless
++          <xref linkend="opt-services.transmission.settings.download-dir"/> is changed,
++          and <literal>${incompleteDir}/</literal> unless
++          <xref linkend="opt-services.transmission.settings.incomplete-dir"/> is changed.
+         '';
+       };
+@@ -119,19 +208,22 @@ in
+         description = ''
+           Path to a JSON file to be merged with the settings.
+           Useful to merge a file which is better kept out of the Nix store
+-          because it contains sensible data like <link linkend="opt-services.transmission.settings">settings.rpc-password</link>.
++          because it contains sensible data like
++          <xref linkend="opt-services.transmission.settings.rpc-password"/>.
+         '';
+         default = "/dev/null";
+         example = "/var/lib/secrets/transmission/settings.json";
+       };
+-      openFirewall = mkEnableOption "opening of the peer port(s) in the firewall";
++      openPeerPorts = mkEnableOption "opening of the peer port(s) in the firewall";
++
++      openRPCPort = mkEnableOption "opening of the RPC port in the firewall";
+       performanceNetParameters = mkEnableOption ''tweaking of kernel parameters
+         to open many more connections at the same time.
  
+         Note that you may also want to increase
+-        <link linkend="opt-services.transmission.settings">settings.peer-limit-global</link>.
++        <xref linkend="opt-services.transmission.settings.peer-limit-global"/>.
+         And be aware that these settings are quite aggressive
+         and might not suite your regular desktop use.
+         For instance, SSH sessions may time out more easily'';
+@@ -152,40 +244,14 @@ in
+       install -d -m '${cfg.downloadDirPermissions}' -o '${cfg.user}' -g '${cfg.group}' '${cfg.settings.download-dir}'
+       '' + optionalString cfg.settings.incomplete-dir-enabled ''
+       install -d -m '${cfg.downloadDirPermissions}' -o '${cfg.user}' -g '${cfg.group}' '${cfg.settings.incomplete-dir}'
++      '' + optionalString cfg.settings.watch-dir-enabled ''
++      install -d -m '${cfg.downloadDirPermissions}' -o '${cfg.user}' -g '${cfg.group}' '${cfg.settings.watch-dir}'
+       '';
+-    assertions = [
+-      { assertion = builtins.match "^/.*" cfg.home != null;
+-        message = "`services.transmission.home' must be an absolute path.";
+-      }
+-      { assertion = types.path.check cfg.settings.download-dir;
+-        message = "`services.transmission.settings.download-dir' must be an absolute path.";
+-      }
+-      { assertion = types.path.check cfg.settings.incomplete-dir;
+-        message = "`services.transmission.settings.incomplete-dir' must be an absolute path.";
+-      }
+-      { assertion = types.path.check cfg.settings.watch-dir;
+-        message = "`services.transmission.settings.watch-dir' must be an absolute path.";
+-      }
+-      { assertion = cfg.settings.script-torrent-done-filename == "" || types.path.check cfg.settings.script-torrent-done-filename;
+-        message = "`services.transmission.settings.script-torrent-done-filename' must be an absolute path.";
+-      }
+-      { assertion = types.port.check cfg.settings.rpc-port;
+-        message = "${toString cfg.settings.rpc-port} is not a valid port number for `services.transmission.settings.rpc-port`.";
+-      }
+-      # In case both port and settings.rpc-port are explicitely defined: they must be the same.
+-      { assertion = !options.services.transmission.port.isDefined || cfg.port == cfg.settings.rpc-port;
+-        message = "`services.transmission.port' is not equal to `services.transmission.settings.rpc-port'";
+-      }
+-    ];
+-
+-    services.transmission.settings =
+-      optionalAttrs options.services.transmission.port.isDefined { rpc-port = cfg.port; };
+-
      systemd.services.transmission = {
        description = "Transmission BitTorrent Service";
 -      after = [ "network.target" ] ++ optional apparmor "apparmor.service";
@@ -853,19 +1226,139 @@ index 014a22bb5a8..57982c20ccd 100644
        wantedBy = [ "multi-user.target" ];
        environment.CURL_CA_BUNDLE = etc."ssl/certs/ca-certificates.crt".source;
  
-@@ -357,61 +357,21 @@ in
+@@ -226,11 +292,9 @@ in
+             cfg.settings.download-dir
+           ] ++
+           optional cfg.settings.incomplete-dir-enabled
+-            cfg.settings.incomplete-dir
+-          ++
+-          optional cfg.settings.watch-dir-enabled
+-            cfg.settings.watch-dir
+-          ;
++            cfg.settings.incomplete-dir ++
++          optional (cfg.settings.watch-dir-enabled && cfg.settings.trash-original-torrent-files)
++            cfg.settings.watch-dir;
+         BindReadOnlyPaths = [
+           # No confinement done of /nix/store here like in systemd-confinement.nix,
+           # an AppArmor profile is provided to get a confinement based upon paths and rights.
+@@ -239,8 +303,10 @@ in
+           "/run"
+           ] ++
+           optional (cfg.settings.script-torrent-done-enabled &&
+-                    cfg.settings.script-torrent-done-filename != "")
+-            cfg.settings.script-torrent-done-filename;
++                    cfg.settings.script-torrent-done-filename != null)
++            cfg.settings.script-torrent-done-filename ++
++          optional (cfg.settings.watch-dir-enabled && !cfg.settings.trash-original-torrent-files)
++            cfg.settings.watch-dir;
+         # The following options are only for optimizing:
+         # systemd-analyze security transmission
+         AmbientCapabilities = "";
+@@ -307,25 +373,28 @@ in
+       };
+     });
+-    networking.firewall = mkIf cfg.openFirewall (
+-      if cfg.settings.peer-port-random-on-start
+-      then
+-        { allowedTCPPortRanges =
+-            [ { from = cfg.settings.peer-port-random-low;
+-                to   = cfg.settings.peer-port-random-high;
+-              }
+-            ];
+-          allowedUDPPortRanges =
+-            [ { from = cfg.settings.peer-port-random-low;
+-                to   = cfg.settings.peer-port-random-high;
+-              }
+-            ];
+-        }
+-      else
+-        { allowedTCPPorts = [ cfg.settings.peer-port ];
+-          allowedUDPPorts = [ cfg.settings.peer-port ];
+-        }
+-    );
++    networking.firewall = mkMerge [
++      (mkIf cfg.openPeerPorts (
++        if cfg.settings.peer-port-random-on-start
++        then
++          { allowedTCPPortRanges =
++              [ { from = cfg.settings.peer-port-random-low;
++                  to   = cfg.settings.peer-port-random-high;
++                }
++              ];
++            allowedUDPPortRanges =
++              [ { from = cfg.settings.peer-port-random-low;
++                  to   = cfg.settings.peer-port-random-high;
++                }
++              ];
++          }
++        else
++          { allowedTCPPorts = [ cfg.settings.peer-port ];
++            allowedUDPPorts = [ cfg.settings.peer-port ];
++          }
++      ))
++      (mkIf cfg.openRPCPort { allowedTCPPorts = [ cfg.settings.rpc-port ]; })
++    ];
+     boot.kernel.sysctl = mkMerge [
+       # Transmission uses a single UDP socket in order to implement multiple uTP sockets,
+@@ -340,113 +409,57 @@ in
+         # Increase the number of available source (local) TCP and UDP ports to 49151.
+         # Usual default is 32768 60999, ie. 28231 ports.
+         # Find out your current usage with: ss -s
+-        "net.ipv4.ip_local_port_range" = "16384 65535";
++        "net.ipv4.ip_local_port_range" = mkDefault "16384 65535";
+         # Timeout faster generic TCP states.
+         # Usual default is 600.
+         # Find out your current usage with: watch -n 1 netstat -nptuo
+-        "net.netfilter.nf_conntrack_generic_timeout" = 60;
++        "net.netfilter.nf_conntrack_generic_timeout" = mkDefault 60;
+         # Timeout faster established but inactive connections.
+         # Usual default is 432000.
+-        "net.netfilter.nf_conntrack_tcp_timeout_established" = 600;
++        "net.netfilter.nf_conntrack_tcp_timeout_established" = mkDefault 600;
+         # Clear immediately TCP states after timeout.
+         # Usual default is 120.
+-        "net.netfilter.nf_conntrack_tcp_timeout_time_wait" = 1;
++        "net.netfilter.nf_conntrack_tcp_timeout_time_wait" = mkDefault 1;
+         # Increase the number of trackable connections.
+         # Usual default is 262144.
+         # Find out your current usage with: conntrack -C
+-        "net.netfilter.nf_conntrack_max" = 1048576;
++        "net.netfilter.nf_conntrack_max" = mkDefault 1048576;
        })
      ];
  
 -    security.apparmor.profiles = mkIf apparmor [
 -      (pkgs.writeText "apparmor-transmission-daemon" ''
+-        include <tunables/global>
 +    security.apparmor.policies."bin.transmission-daemon".profile = ''
-         include <tunables/global>
--
-         ${pkgs.transmission}/bin/transmission-daemon {
-           include <abstractions/base>
-           include <abstractions/nameservice>
--
++      include "${pkgs.transmission.apparmor}/bin.transmission-daemon"
++    '';
++    security.apparmor.includes."local/bin.transmission-daemon" = ''
++      r ${config.systemd.services.transmission.environment.CURL_CA_BUNDLE},
+-        ${pkgs.transmission}/bin/transmission-daemon {
+-          include <abstractions/base>
+-          include <abstractions/nameservice>
++      owner rw ${cfg.home}/${settingsDir}/**,
++      rw ${cfg.settings.download-dir}/**,
++      ${optionalString cfg.settings.incomplete-dir-enabled ''
++        rw ${cfg.settings.incomplete-dir}/**,
++      ''}
++      ${optionalString cfg.settings.watch-dir-enabled ''
++        r${optionalString cfg.settings.trash-original-torrent-files "w"} ${cfg.settings.watch-dir}/**,
++      ''}
++      profile dirs {
++        rw ${cfg.settings.download-dir}/**,
++        ${optionalString cfg.settings.incomplete-dir-enabled ''
++          rw ${cfg.settings.incomplete-dir}/**,
++        ''}
++        ${optionalString cfg.settings.watch-dir-enabled ''
++          r${optionalString cfg.settings.trash-original-torrent-files "w"} ${cfg.settings.watch-dir}/**,
++        ''}
++      }
 -          # NOTE: https://github.com/NixOS/nixpkgs/pull/93457
 -          # will remove the need for these by fixing <abstractions/base>
 -          r ${etc."hosts".source},
@@ -897,49 +1390,73 @@ index 014a22bb5a8..57982c20ccd 100644
 -          mr ${getLib pkgs.openssl}/lib/libcrypto*.so*,
 -          mr ${getLib pkgs.openssl}/lib/libssl*.so*,
 -          mr ${getLib pkgs.systemd}/lib/libsystemd*.so*,
--          mr ${getLib pkgs.utillinuxMinimal.out}/lib/libblkid.so*,
--          mr ${getLib pkgs.utillinuxMinimal.out}/lib/libmount.so*,
--          mr ${getLib pkgs.utillinuxMinimal.out}/lib/libuuid.so*,
+-          mr ${getLib pkgs.util-linuxMinimal.out}/lib/libblkid.so*,
+-          mr ${getLib pkgs.util-linuxMinimal.out}/lib/libmount.so*,
+-          mr ${getLib pkgs.util-linuxMinimal.out}/lib/libuuid.so*,
 -          mr ${getLib pkgs.xz}/lib/liblzma*.so*,
 -          mr ${getLib pkgs.zlib}/lib/libz*.so*,
-+          include <abstractions/ssl_certs>
-+          include "${pkgs.apparmorRulesFromClosure {} [pkgs.transmission]}"
-+          include <local/bin.transmission-daemon>
-           r @{PROC}/sys/kernel/random/uuid,
-           r @{PROC}/sys/vm/overcommit_memory,
+-
+-          r @{PROC}/sys/kernel/random/uuid,
+-          r @{PROC}/sys/vm/overcommit_memory,
 -          # @{pid} is not a kernel variable yet but a regexp
 -          #r @{PROC}/@{pid}/environ,
-+          r @{PROC}/@{pid}/environ,
-           r @{PROC}/@{pid}/mounts,
-           rwk /tmp/tr_session_id_*,
+-          r @{PROC}/@{pid}/mounts,
+-          rwk /tmp/tr_session_id_*,
+-          r /run/systemd/resolve/stub-resolv.conf,
 -
 -          r ${pkgs.openssl.out}/etc/**,
-           r ${config.systemd.services.transmission.environment.CURL_CA_BUNDLE},
+-          r ${config.systemd.services.transmission.environment.CURL_CA_BUNDLE},
 -          r ${pkgs.transmission}/share/transmission/**,
-           owner rw ${cfg.home}/${settingsDir}/**,
-           rw ${cfg.settings.download-dir}/**,
-@@ -439,12 +399,9 @@ in
-             # https://gitlab.com/apparmor/apparmor/-/wikis/AppArmorStacking#seccomp-and-no_new_privs
-             px ${cfg.settings.script-torrent-done-filename} -> &@{dirs},
-           ''}
+-
+-          owner rw ${cfg.home}/${settingsDir}/**,
+-          rw ${cfg.settings.download-dir}/**,
+-          ${optionalString cfg.settings.incomplete-dir-enabled ''
+-            rw ${cfg.settings.incomplete-dir}/**,
+-          ''}
+-          ${optionalString cfg.settings.watch-dir-enabled ''
+-            rw ${cfg.settings.watch-dir}/**,
+-          ''}
+-          profile dirs {
+-            rw ${cfg.settings.download-dir}/**,
+-            ${optionalString cfg.settings.incomplete-dir-enabled ''
+-              rw ${cfg.settings.incomplete-dir}/**,
+-            ''}
+-            ${optionalString cfg.settings.watch-dir-enabled ''
+-              rw ${cfg.settings.watch-dir}/**,
+-            ''}
+-          }
+-
+-          ${optionalString (cfg.settings.script-torrent-done-enabled &&
+-                            cfg.settings.script-torrent-done-filename != "") ''
+-            # Stack transmission_directories profile on top of
+-            # any existing profile for script-torrent-done-filename
+-            # FIXME: to be tested as I'm not sure it works well with NoNewPrivileges=
+-            # https://gitlab.com/apparmor/apparmor/-/wikis/AppArmorStacking#seccomp-and-no_new_privs
+-            px ${cfg.settings.script-torrent-done-filename} -> &@{dirs},
+-          ''}
 -
 -          # FIXME: enable customizing using https://github.com/NixOS/nixpkgs/pull/93457
 -          # include <local/transmission-daemon>
-         }
+-        }
 -      '')
 -    ];
++      ${optionalString (cfg.settings.script-torrent-done-enabled &&
++                        cfg.settings.script-torrent-done-filename != null) ''
++        # Stack transmission_directories profile on top of
++        # any existing profile for script-torrent-done-filename
++        # FIXME: to be tested as I'm not sure it works well with NoNewPrivileges=
++        # https://gitlab.com/apparmor/apparmor/-/wikis/AppArmorStacking#seccomp-and-no_new_privs
++        px ${cfg.settings.script-torrent-done-filename} -> &@{dirs},
++      ''}
 +    '';
-+    security.apparmor.includes."local/bin.transmission-daemon" = "";
    };
  
    meta.maintainers = with lib.maintainers; [ julm ];
 diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix
-index e5bd5775368..02723c6a164 100644
+index f730ec82bdf..3bfb59a8848 100644
 --- a/nixos/modules/tasks/network-interfaces.nix
 +++ b/nixos/modules/tasks/network-interfaces.nix
-@@ -1094,6 +1094,21 @@ in
+@@ -1111,6 +1111,21 @@ in
      } else {
        ping.source = "${pkgs.iputils.out}/bin/ping";
      };
@@ -984,18 +1501,20 @@ index f484d5ee59a..0f8b22a45df 100644
    };
  }
 diff --git a/nixos/modules/virtualisation/lxd.nix b/nixos/modules/virtualisation/lxd.nix
-index 3958fc2c1d7..876956f654b 100644
+index 96e8d68ae50..6b6f4b6e652 100644
 --- a/nixos/modules/virtualisation/lxd.nix
 +++ b/nixos/modules/virtualisation/lxd.nix
-@@ -93,11 +93,15 @@ in
+@@ -97,11 +97,17 @@ in {
+     # does a bunch of unrelated things.
+     systemd.tmpfiles.rules = [ "d /var/lib/lxc/rootfs 0755 root root -" ];
  
-     security.apparmor = {
-       enable = true;
--      profiles = [
--        "${cfg.lxcPackage}/etc/apparmor.d/usr.bin.lxc-start"
--        "${cfg.lxcPackage}/etc/apparmor.d/lxc-containers"
--      ];
-       packages = [ cfg.lxcPackage ];
+-    security.apparmor.packages = [ cfg.lxcPackage ];
+-    security.apparmor.profiles = [
+-      "${cfg.lxcPackage}/etc/apparmor.d/lxc-containers"
+-      "${cfg.lxcPackage}/etc/apparmor.d/usr.bin.lxc-start"
+-    ];
++    security.apparmor = {
++      packages = [ cfg.lxcPackage ];
 +      policies = {
 +        "bin.lxc-start".profile = ''
 +          include ${cfg.lxcPackage}/etc/apparmor.d/usr.bin.lxc-start
@@ -1004,14 +1523,167 @@ index 3958fc2c1d7..876956f654b 100644
 +          include ${cfg.lxcPackage}/etc/apparmor.d/lxc-containers
 +        '';
 +      };
-     };
++    };
  
-     systemd.services.lxd = {
+     # TODO: remove once LXD gets proper support for cgroupsv2
+     # (currently most of the e.g. CPU accounting stuff doesn't work)
+diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
+index fb45ec1a310..957d052ace1 100644
+--- a/nixos/tests/all-tests.nix
++++ b/nixos/tests/all-tests.nix
+@@ -25,6 +25,7 @@ in
+   acme = handleTest ./acme.nix {};
+   agda = handleTest ./agda.nix {};
+   ammonite = handleTest ./ammonite.nix {};
++  apparmor = handleTest ./apparmor.nix {};
+   atd = handleTest ./atd.nix {};
+   avahi = handleTest ./avahi.nix {};
+   avahi-with-resolved = handleTest ./avahi.nix { networkd = true; };
+diff --git a/nixos/tests/apparmor.nix b/nixos/tests/apparmor.nix
+new file mode 100644
+index 00000000000..c6daa8e67de
+--- /dev/null
++++ b/nixos/tests/apparmor.nix
+@@ -0,0 +1,82 @@
++import ./make-test-python.nix ({ pkgs, ... } : {
++  name = "apparmor";
++  meta = with pkgs.lib.maintainers; {
++    maintainers = [ julm ];
++  };
++
++  machine =
++    { lib, pkgs, config, ... }:
++    with lib;
++    {
++      security.apparmor.enable = mkDefault true;
++    };
++
++  testScript =
++    ''
++      machine.wait_for_unit("multi-user.target")
++
++      with subtest("AppArmor profiles are loaded"):
++          machine.succeed("systemctl status apparmor.service")
++
++      # AppArmor securityfs
++      with subtest("AppArmor securityfs is mounted"):
++          machine.succeed("mountpoint -q /sys/kernel/security")
++          machine.succeed("cat /sys/kernel/security/apparmor/profiles")
++
++      # Test apparmorRulesFromClosure by:
++      # 1. Prepending a string of the relevant packages' name and version on each line.
++      # 2. Sorting according to those strings.
++      # 3. Removing those prepended strings.
++      # 4. Using `diff` against the expected output.
++      with subtest("apparmorRulesFromClosure"):
++          machine.succeed(
++              "${pkgs.diffutils}/bin/diff ${pkgs.writeText "expected.rules" ''
++                  mr ${pkgs.bash}/lib/**.so*,
++                  r ${pkgs.bash},
++                  r ${pkgs.bash}/etc/**,
++                  r ${pkgs.bash}/lib/**,
++                  r ${pkgs.bash}/share/**,
++                  x ${pkgs.bash}/foo/**,
++                  mr ${pkgs.glibc}/lib/**.so*,
++                  r ${pkgs.glibc},
++                  r ${pkgs.glibc}/etc/**,
++                  r ${pkgs.glibc}/lib/**,
++                  r ${pkgs.glibc}/share/**,
++                  x ${pkgs.glibc}/foo/**,
++                  mr ${pkgs.libcap}/lib/**.so*,
++                  r ${pkgs.libcap},
++                  r ${pkgs.libcap}/etc/**,
++                  r ${pkgs.libcap}/lib/**,
++                  r ${pkgs.libcap}/share/**,
++                  x ${pkgs.libcap}/foo/**,
++                  mr ${pkgs.libcap.lib}/lib/**.so*,
++                  r ${pkgs.libcap.lib},
++                  r ${pkgs.libcap.lib}/etc/**,
++                  r ${pkgs.libcap.lib}/lib/**,
++                  r ${pkgs.libcap.lib}/share/**,
++                  x ${pkgs.libcap.lib}/foo/**,
++                  mr ${pkgs.libidn2.out}/lib/**.so*,
++                  r ${pkgs.libidn2.out},
++                  r ${pkgs.libidn2.out}/etc/**,
++                  r ${pkgs.libidn2.out}/lib/**,
++                  r ${pkgs.libidn2.out}/share/**,
++                  x ${pkgs.libidn2.out}/foo/**,
++                  mr ${pkgs.libunistring}/lib/**.so*,
++                  r ${pkgs.libunistring},
++                  r ${pkgs.libunistring}/etc/**,
++                  r ${pkgs.libunistring}/lib/**,
++                  r ${pkgs.libunistring}/share/**,
++                  x ${pkgs.libunistring}/foo/**,
++              ''} ${pkgs.runCommand "actual.rules" { preferLocalBuild = true; } ''
++                  ${pkgs.gnused}/bin/sed -e 's:^[^ ]* ${builtins.storeDir}/[^,/-]*-\([^/,]*\):\1 \0:' ${
++                      pkgs.apparmorRulesFromClosure {
++                        name = "ping";
++                        additionalRules = ["x $path/foo/**"];
++                      } [ pkgs.libcap ]
++                  } |
++                  ${pkgs.coreutils}/bin/sort -n -k1 |
++                  ${pkgs.gnused}/bin/sed -e 's:^[^ ]* ::' >$out
++              ''}"
++          )
++    '';
++})
+diff --git a/pkgs/applications/networking/p2p/transmission/default.nix b/pkgs/applications/networking/p2p/transmission/default.nix
+index 7e8b6b671cd..b2519eb2fa0 100644
+--- a/pkgs/applications/networking/p2p/transmission/default.nix
++++ b/pkgs/applications/networking/p2p/transmission/default.nix
+@@ -20,6 +20,7 @@
+ , enableSystemd ? stdenv.isLinux
+ , enableDaemon ? true
+ , enableCli ? true
++, apparmorRulesFromClosure
+ }:
+ let
+@@ -37,6 +38,8 @@ in stdenv.mkDerivation {
+     fetchSubmodules = true;
+   };
++  outputs = [ "out" "apparmor" ];
++
+   cmakeFlags =
+     let
+       mkFlag = opt: if opt then "ON" else "OFF";
+@@ -72,6 +75,30 @@ in stdenv.mkDerivation {
+   NIX_LDFLAGS = lib.optionalString stdenv.isDarwin "-framework CoreFoundation";
++  postInstall = ''
++    install -D -m 644 /dev/stdin $apparmor/bin.transmission-daemon <<EOF
++    include <tunables/global>
++    $out/bin/transmission-daemon {
++      include <abstractions/base>
++      include <abstractions/nameservice>
++      include <abstractions/ssl_certs>
++      include "${apparmorRulesFromClosure { name = "transmission-daemon"; } ([
++        curl libevent openssl pcre zlib
++      ] ++ lib.optionals enableSystemd [ systemd ]
++        ++ lib.optionals stdenv.isLinux [ inotify-tools ]
++      )}"
++      r @{PROC}/sys/kernel/random/uuid,
++      r @{PROC}/sys/vm/overcommit_memory,
++      r @{PROC}/@{pid}/environ,
++      r @{PROC}/@{pid}/mounts,
++      rwk /tmp/tr_session_id_*,
++      r /run/systemd/resolve/stub-resolv.conf,
++
++      include <local/bin.transmission-daemon>
++    }
++    EOF
++  '';
++
+   meta = {
+     description = "A fast, easy and free BitTorrent client";
+     longDescription = ''
 diff --git a/pkgs/os-specific/linux/apparmor/default.nix b/pkgs/os-specific/linux/apparmor/default.nix
-index 0e10add5561..8806f6c50d3 100644
+index 935b5e65b1f..a07cd5070d2 100644
 --- a/pkgs/os-specific/linux/apparmor/default.nix
 +++ b/pkgs/os-specific/linux/apparmor/default.nix
-@@ -10,6 +10,13 @@
+@@ -10,26 +10,37 @@
  , pam
  , libnotify
  , buildPackages
@@ -1025,8 +1697,25 @@ index 0e10add5561..8806f6c50d3 100644
  }:
  
  let
-@@ -38,6 +45,12 @@ let
-     sha256 = "0xw028iqp69j9mxv0kbwraplgkj5i5djdlgf0anpkc5cdbsf96r9";
+-  apparmor-series = "2.13";
+-  apparmor-patchver = "6";
+-  apparmor-version = apparmor-series + "." + apparmor-patchver;
++  apparmor-version = "3.0.1";
+   apparmor-meta = component: with lib; {
+     homepage = "https://apparmor.net/";
+     description = "A mandatory access control system - ${component}";
+     license = licenses.gpl2;
+-    maintainers = with maintainers; [ phreedom thoughtpolice joachifm ];
++    maintainers = with maintainers; [ joachifm julm phreedom thoughtpolice ];
+     platforms = platforms.linux;
+   };
+   apparmor-sources = fetchurl {
+-    url = "https://launchpad.net/apparmor/${apparmor-series}/${apparmor-version}/+download/apparmor-${apparmor-version}.tar.gz";
+-    sha256 = "13xshy7905d9q9n8d8i0jmdi9m36wr525g4wlsp8k21n7yvvh9j4";
++    url = "https://launchpad.net/apparmor/${lib.versions.majorMinor apparmor-version}/${apparmor-version}/+download/apparmor-${apparmor-version}.tar.gz";
++    sha256 = "096zbg3v7b51x7f1ly61mzd3iy9alad6sd4lam98j2d6v5ragbcg";
    };
  
 +  aa-teardown = writeShellScript "aa-teardown" ''
@@ -1036,16 +1725,50 @@ index 0e10add5561..8806f6c50d3 100644
 +  '';
 +
    prePatchCommon = ''
-     patch -p1 < ${gnumake43Patch}
      chmod a+x ./common/list_capabilities.sh ./common/list_af_names.sh
-@@ -149,6 +162,15 @@ let
+     patchShebangs ./common/list_capabilities.sh ./common/list_af_names.sh
+@@ -45,12 +56,6 @@ let
+       name = "0003-Added-missing-typedef-definitions-on-parser.patch";
+       sha256 = "0yyaqz8jlmn1bm37arggprqz0njb4lhjni2d9c8qfqj0kll0bam0";
+     })
+-    (fetchpatch {
+-      url = "https://git.alpinelinux.org/aports/plain/testing/apparmor/0007-Do-not-build-install-vim-file-with-utils-package.patch?id=74b8427cc21f04e32030d047ae92caa618105b53";
+-      name = "0007-Do-not-build-install-vim-file-with-utils-package.patch";
+-      sha256 = "1m4dx901biqgnr4w4wz8a2z9r9dxyw7wv6m6mqglqwf2lxinqmp4";
+-    })
+-    # (alpine patches {1,4,5,6,8} are needed for apparmor 2.11, but not 2.12)
+     ];
+   # Set to `true` after the next FIXME gets fixed or this gets some
+@@ -121,7 +126,11 @@ let
+       libapparmor.python
+     ];
+-    prePatch = prePatchCommon + ''
++    prePatch = prePatchCommon +
++      # Do not build vim file
++      lib.optionalString stdenv.hostPlatform.isMusl ''
++        sed -i ./utils/Makefile -e "/\<vim\>/d"
++      '' + ''
+       substituteInPlace ./utils/apparmor/easyprof.py --replace "/sbin/apparmor_parser" "${apparmor-parser}/bin/apparmor_parser"
+       substituteInPlace ./utils/apparmor/aa.py --replace "/sbin/apparmor_parser" "${apparmor-parser}/bin/apparmor_parser"
+       substituteInPlace ./utils/logprof.conf --replace "/sbin/apparmor_parser" "${apparmor-parser}/bin/apparmor_parser"
+@@ -132,7 +141,8 @@ let
+     installFlags = [ "DESTDIR=$(out)" "BINDIR=$(out)/bin" "VIM_INSTALL_PATH=$(out)/share" "PYPREFIX=" ];
+     postInstall = ''
+-      for prog in aa-audit aa-autodep aa-cleanprof aa-complain aa-disable aa-enforce aa-genprof aa-logprof aa-mergeprof aa-status aa-unconfined ; do
++      sed -i $out/bin/aa-unconfined -e "/my_env\['PATH'\]/d"
++      for prog in aa-audit aa-autodep aa-cleanprof aa-complain aa-disable aa-enforce aa-genprof aa-logprof aa-mergeprof aa-unconfined ; do
+         wrapProgram $out/bin/$prog --prefix PYTHONPATH : "$out/lib/${python.libPrefix}/site-packages:$PYTHONPATH"
+       done
+@@ -140,6 +150,13 @@ let
        # aa-notify checks its name and does not work named ".aa-notify-wrapped"
        mv $out/bin/aa-notify $out/bin/aa-notify-wrapped
        makeWrapper ${perl}/bin/perl $out/bin/aa-notify --set PERL5LIB ${libapparmor}/${perl.libPrefix} --add-flags $out/bin/aa-notify-wrapped
 +
 +      substituteInPlace $out/bin/aa-remove-unknown \
-+       --replace "/usr/bin/aa-status" "$out/bin/aa-status" \
-+       --replace "/sbin/modprobe" "${kmod}/bin/modprobe" \
 +       --replace "/lib/apparmor/rc.apparmor.functions" "${apparmor-parser}/lib/apparmor/rc.apparmor.functions"
 +      wrapProgram $out/bin/aa-remove-unknown \
 +       --prefix PATH : ${lib.makeBinPath [gawk]}
@@ -1054,7 +1777,16 @@ index 0e10add5561..8806f6c50d3 100644
      '';
  
      inherit doCheck;
-@@ -197,6 +219,9 @@ let
+@@ -167,7 +184,7 @@ let
+     prePatch = prePatchCommon;
+     postPatch = "cd ./binutils";
+     makeFlags = [ "LANGS=" "USE_SYSTEM=1" ];
+-    installFlags = [ "DESTDIR=$(out)" "BINDIR=$(out)/bin" ];
++    installFlags = [ "DESTDIR=$(out)" "BINDIR=$(out)/bin" "SBINDIR=$(out)/bin" ];
+     inherit doCheck;
+@@ -188,6 +205,9 @@ let
        substituteInPlace ./parser/Makefile --replace "/usr/include/linux/capability.h" "${linuxHeaders}/include/linux/capability.h"
        ## techdoc.pdf still doesn't build ...
        substituteInPlace ./parser/Makefile --replace "manpages htmlmanpages pdf" "manpages htmlmanpages"
@@ -1064,7 +1796,7 @@ index 0e10add5561..8806f6c50d3 100644
      '';
      inherit patches;
      postPatch = "cd ./parser";
-@@ -258,8 +283,32 @@ let
+@@ -249,8 +269,35 @@ let
      meta = apparmor-meta "kernel patches";
    };
  
@@ -1087,7 +1819,10 @@ index 0e10add5561..8806f6c50d3 100644
 +        # eg. glibc-2.30/lib/gconv/gconv-modules
 +        "r $path/lib/**"
 +      ]
-+    }: rootPaths: runCommand "apparmor-closure-rules" {} ''
++    , name ? ""
++    }: rootPaths: runCommand
++      ( "apparmor-closure-rules"
++      + lib.optionalString (name != "") "-${name}" ) {} ''
 +    touch $out
 +    while read -r path
 +    do printf >>$out "%s,\n" ${lib.concatMapStringsSep " " (x: "\"${x}\"") (baseRules ++ additionalRules)}
@@ -1098,7 +1833,7 @@ index 0e10add5561..8806f6c50d3 100644
  {
    inherit
      libapparmor
-@@ -268,5 +317,6 @@ in
+@@ -259,5 +306,6 @@ in
      apparmor-parser
      apparmor-pam
      apparmor-profiles
@@ -1145,39 +1880,39 @@ index 00000000000..ebc1baaa92d
 +   echo ": Skipped."
 +}
 diff --git a/pkgs/os-specific/linux/iputils/default.nix b/pkgs/os-specific/linux/iputils/default.nix
-index 3bb653ebcf7..26953bcf91b 100644
+index 56942d6d420..122a9ca1b7b 100644
 --- a/pkgs/os-specific/linux/iputils/default.nix
 +++ b/pkgs/os-specific/linux/iputils/default.nix
 @@ -1,6 +1,7 @@
- { stdenv, fetchFromGitHub, fetchpatch
- , meson, ninja, pkgconfig, gettext, libxslt, docbook_xsl_ns
+ { lib, stdenv, fetchFromGitHub
+ , meson, ninja, pkg-config, gettext, libxslt, docbook_xsl_ns
  , libcap, libidn2
 +, apparmorRulesFromClosure
  }:
  
- with stdenv.lib;
-@@ -30,6 +31,8 @@ in stdenv.mkDerivation rec {
-     })
-   ];
+ let
+@@ -20,6 +21,8 @@ in stdenv.mkDerivation rec {
+     sha256 = "08j2hfgnfh31vv9rn1ml7090j2lsvm9wdpdz13rz60rmyzrx9dq3";
+   };
  
 +  outputs = ["out" "apparmor"];
 +
    mesonFlags = [
      "-DBUILD_RARPD=true"
      "-DBUILD_TRACEROUTE6=true"
-@@ -44,6 +47,25 @@ in stdenv.mkDerivation rec {
-   nativeBuildInputs = [ meson ninja pkgconfig gettext libxslt.bin docbook_xsl_ns ];
+@@ -34,6 +37,25 @@ in stdenv.mkDerivation rec {
+   nativeBuildInputs = [ meson ninja pkg-config gettext libxslt.bin docbook_xsl_ns ];
    buildInputs = [ libcap ]
-     ++ optional (!stdenv.hostPlatform.isMusl) libidn2;
+     ++ lib.optional (!stdenv.hostPlatform.isMusl) libidn2;
 +  postInstall = ''
-+    install -D /dev/stdin $apparmor/bin.ping <<EOF
++    install -D -m 644 /dev/stdin $apparmor/bin.ping <<EOF
 +    include <tunables/global>
 +    $out/bin/ping {
 +      include <abstractions/base>
 +      include <abstractions/consoles>
 +      include <abstractions/nameservice>
-+      include "${apparmorRulesFromClosure {}
-+       ([libcap] ++ optional (!stdenv.hostPlatform.isMusl) libidn2)}"
++      include "${apparmorRulesFromClosure { name = "ping"; }
++       ([libcap] ++ lib.optional (!stdenv.hostPlatform.isMusl) libidn2)}"
 +      include <local/bin.ping>
 +      capability net_raw,
 +      network inet raw,
@@ -1189,10 +1924,10 @@ index 3bb653ebcf7..26953bcf91b 100644
 +    EOF
 +  '';
  
-   meta = {
+   meta = with lib; {
      description = "A set of small useful utilities for Linux networking";
 diff --git a/pkgs/tools/networking/inetutils/default.nix b/pkgs/tools/networking/inetutils/default.nix
-index 1290ec2bdb1..bcc4237f434 100644
+index 1290ec2bdb1..fe5a0d91585 100644
 --- a/pkgs/tools/networking/inetutils/default.nix
 +++ b/pkgs/tools/networking/inetutils/default.nix
 @@ -1,4 +1,6 @@
@@ -1217,12 +1952,12 @@ index 1290ec2bdb1..bcc4237f434 100644
    installFlags = [ "SUIDMODE=" ];
  
 +  postInstall = ''
-+    install -D /dev/stdin $apparmor/bin.ping <<EOF
++    install -D -m 644 /dev/stdin $apparmor/bin.ping <<EOF
 +    $out/bin/ping {
 +      include <abstractions/base>
 +      include <abstractions/consoles>
 +      include <abstractions/nameservice>
-+      include "${apparmorRulesFromClosure {} [stdenv.cc.libc]}"
++      include "${apparmorRulesFromClosure { name = "ping"; } [stdenv.cc.libc]}"
 +      include <local/bin.ping>
 +      capability net_raw,
 +      network inet raw,
@@ -1236,15 +1971,15 @@ index 1290ec2bdb1..bcc4237f434 100644
      description = "Collection of common network programs";
  
 diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
-index 8afc133f51b..4dcb1178730 100644
+index 8dfaf25fc04..3c055686e2e 100644
 --- a/pkgs/top-level/all-packages.nix
 +++ b/pkgs/top-level/all-packages.nix
-@@ -17413,7 +17413,7 @@ in
+@@ -19105,7 +19105,7 @@ in
  
    inherit (callPackages ../os-specific/linux/apparmor { python = python3; })
      libapparmor apparmor-utils apparmor-bin-utils apparmor-parser apparmor-pam
 -    apparmor-profiles apparmor-kernel-patches;
 +    apparmor-profiles apparmor-kernel-patches apparmorRulesFromClosure;
  
-   atop = callPackage ../os-specific/linux/atop { };
+   aseq2json = callPackage ../os-specific/linux/aseq2json {};