nix: update inputs
[sourcephile-nix.git] / nixpkgs / patches / apparmor.diff
index ea72556b0d4bd81821d6eac87565b677dff56445..5fe95b5e74265082d9f1bc338f216985fb31d01e 100644 (file)
@@ -1,8 +1,8 @@
 diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix
-index b166e7bf01f..c059c2bb002 100644
+index 6270ac778ae..57f3dda64cd 100644
 --- a/maintainers/maintainer-list.nix
 +++ b/maintainers/maintainer-list.nix
-@@ -4657,7 +4657,7 @@
+@@ -4779,7 +4779,7 @@
      name = "Julien Dehos";
    };
    julm = {
@@ -12,10 +12,10 @@ index b166e7bf01f..c059c2bb002 100644
      githubId = 21160136;
      name = "Julien Moutinho";
 diff --git a/nixos/doc/manual/release-notes/rl-2105.xml b/nixos/doc/manual/release-notes/rl-2105.xml
-index 6dd14d6051e..f485eb114cc 100644
+index b7947293c01..8abee64734d 100644
 --- a/nixos/doc/manual/release-notes/rl-2105.xml
 +++ b/nixos/doc/manual/release-notes/rl-2105.xml
-@@ -662,6 +662,24 @@ self: super:
+@@ -795,6 +795,23 @@ environment.systemPackages = [
       The option's description was incorrect regarding ownership management and has been simplified greatly.
      </para>
     </listitem>
@@ -31,10 +31,9 @@ index 6dd14d6051e..f485eb114cc 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>
@@ -103,10 +102,10 @@ index a3eb55d8a42..fc35993b5a8 100644
    };
  }
 diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
-index 3055459e781..d9cc86fcd4e 100644
+index 4a63a09ab84..43f052d150e 100644
 --- a/nixos/modules/module-list.nix
 +++ b/nixos/modules/module-list.nix
-@@ -199,7 +199,6 @@
+@@ -201,7 +201,6 @@
    ./rename.nix
    ./security/acme.nix
    ./security/apparmor.nix
@@ -114,6 +113,18 @@ index 3055459e781..d9cc86fcd4e 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..dfa695b81bb 100644
+index cfc65b347bc..8683d2b487c 100644
 --- a/nixos/modules/security/apparmor.nix
 +++ b/nixos/modules/security/apparmor.nix
-@@ -1,59 +1,207 @@
+@@ -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..dfa695b81bb 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..dfa695b81bb 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..dfa695b81bb 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..dfa695b81bb 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..dfa695b81bb 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.";
@@ -324,15 +341,15 @@ index cfc65b347bc..dfa695b81bb 100644
 +    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 = ''
 +    '';
@@ -358,12 +375,13 @@ index cfc65b347bc..dfa695b81bb 100644
 +          # 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
++          ${config.users.defaultUserShell} = icnu
 +      '';
 +      footer = "${pkgs.apparmor-utils}/etc/apparmor/logprof.conf";
 +      passAsFile = [ "header" ];
@@ -401,17 +419,17 @@ index cfc65b347bc..dfa695b81bb 100644
 +          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).
@@ -419,7 +437,7 @@ index cfc65b347bc..dfa695b81bb 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";
@@ -427,26 +445,28 @@ index cfc65b347bc..dfa695b81bb 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
@@ -466,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"
@@ -546,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"
@@ -610,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"
 +  '';
@@ -644,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"
@@ -652,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,
@@ -721,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 = "/**"; }}
 +  '';
 +};
 +}
@@ -753,69 +787,104 @@ 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 103cf205012..8216c03795a 100644
+index 103cf205012..1c49131d789 100644
 --- a/nixos/modules/security/pam.nix
 +++ b/nixos/modules/security/pam.nix
-@@ -895,6 +895,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
++      '';
    };
  
  }
@@ -1432,18 +1501,20 @@ index f484d5ee59a..0f8b22a45df 100644
    };
  }
 diff --git a/nixos/modules/virtualisation/lxd.nix b/nixos/modules/virtualisation/lxd.nix
-index 4b2adf4cc69..335dc67673f 100644
+index 96e8d68ae50..6b6f4b6e652 100644
 --- a/nixos/modules/virtualisation/lxd.nix
 +++ b/nixos/modules/virtualisation/lxd.nix
-@@ -83,11 +83,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
@@ -1452,11 +1523,112 @@ index 4b2adf4cc69..335dc67673f 100644
 +          include ${cfg.lxcPackage}/etc/apparmor.d/lxc-containers
 +        '';
 +      };
-     };
++    };
  
      # 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 8cc674b1ea7..bf09c4be1db 100644
+index 7e8b6b671cd..b2519eb2fa0 100644
 --- a/pkgs/applications/networking/p2p/transmission/default.nix
 +++ b/pkgs/applications/networking/p2p/transmission/default.nix
 @@ -20,6 +20,7 @@
@@ -1508,7 +1680,7 @@ index 8cc674b1ea7..bf09c4be1db 100644
      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 935b5e65b1f..5ec86c49660 100644
+index 935b5e65b1f..a07cd5070d2 100644
 --- a/pkgs/os-specific/linux/apparmor/default.nix
 +++ b/pkgs/os-specific/linux/apparmor/default.nix
 @@ -10,26 +10,37 @@
@@ -1650,7 +1822,7 @@ index 935b5e65b1f..5ec86c49660 100644
 +    , name ? ""
 +    }: rootPaths: runCommand
 +      ( "apparmor-closure-rules"
-+      + lib.optionalString (name != "") "-${name}") {} ''
++      + lib.optionalString (name != "") "-${name}" ) {} ''
 +    touch $out
 +    while read -r path
 +    do printf >>$out "%s,\n" ${lib.concatMapStringsSep " " (x: "\"${x}\"") (baseRules ++ additionalRules)}
@@ -1799,10 +1971,10 @@ index 1290ec2bdb1..fe5a0d91585 100644
      description = "Collection of common network programs";
  
 diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix
-index bc5c1b88046..b3fee4ce167 100644
+index 8dfaf25fc04..3c055686e2e 100644
 --- a/pkgs/top-level/all-packages.nix
 +++ b/pkgs/top-level/all-packages.nix
-@@ -18758,7 +18758,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