about summary refs log tree commit diff
path: root/nixpkgs/nixos
diff options
context:
space:
mode:
authorAlyssa Ross <hi@alyssa.is>2019-05-17 10:56:54 +0000
committerAlyssa Ross <hi@alyssa.is>2019-05-17 10:56:54 +0000
commitc1d22074139ab0d048a05b5e5116265d099114d6 (patch)
tree97977009422d675f8930f97c309b010481289e72 /nixpkgs/nixos
parent4dc8afe4fd6b18437150129e0a1ecc23c6a1c0b9 (diff)
parentbc9df0f66110039e495b6debe3a6cda4a1bb0fed (diff)
downloadnixlib-c1d22074139ab0d048a05b5e5116265d099114d6.tar
nixlib-c1d22074139ab0d048a05b5e5116265d099114d6.tar.gz
nixlib-c1d22074139ab0d048a05b5e5116265d099114d6.tar.bz2
nixlib-c1d22074139ab0d048a05b5e5116265d099114d6.tar.lz
nixlib-c1d22074139ab0d048a05b5e5116265d099114d6.tar.xz
nixlib-c1d22074139ab0d048a05b5e5116265d099114d6.tar.zst
nixlib-c1d22074139ab0d048a05b5e5116265d099114d6.zip
Merge commit 'bc9df0f66110039e495b6debe3a6cda4a1bb0fed'
Diffstat (limited to 'nixpkgs/nixos')
-rw-r--r--nixpkgs/nixos/modules/config/malloc.nix86
-rw-r--r--nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl15
-rw-r--r--nixpkgs/nixos/modules/misc/ids.nix2
-rw-r--r--nixpkgs/nixos/modules/module-list.nix3
-rw-r--r--nixpkgs/nixos/modules/profiles/hardened.nix2
-rw-r--r--nixpkgs/nixos/modules/programs/xss-lock.nix19
-rw-r--r--nixpkgs/nixos/modules/programs/zmap.nix18
-rw-r--r--nixpkgs/nixos/modules/rename.nix3
-rw-r--r--nixpkgs/nixos/modules/security/apparmor.nix2
-rw-r--r--nixpkgs/nixos/modules/security/misc.nix18
-rw-r--r--nixpkgs/nixos/modules/security/rngd.nix38
-rw-r--r--nixpkgs/nixos/modules/services/backup/znapzend.nix27
-rw-r--r--nixpkgs/nixos/modules/services/databases/foundationdb.nix11
-rw-r--r--nixpkgs/nixos/modules/services/logging/journalbeat.nix43
-rw-r--r--nixpkgs/nixos/modules/services/misc/jellyfin.nix6
-rw-r--r--nixpkgs/nixos/modules/services/misc/paperless.nix185
-rw-r--r--nixpkgs/nixos/modules/services/monitoring/vnstat.nix19
-rw-r--r--nixpkgs/nixos/modules/services/networking/tinc.nix1
-rw-r--r--nixpkgs/nixos/modules/services/security/fprintd.nix20
-rw-r--r--nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix5
-rw-r--r--nixpkgs/nixos/modules/services/x11/display-managers/sddm.nix9
-rw-r--r--nixpkgs/nixos/modules/system/boot/binfmt.nix314
-rw-r--r--nixpkgs/nixos/modules/system/boot/kexec.nix12
-rw-r--r--nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix3
-rw-r--r--nixpkgs/nixos/modules/system/boot/luksroot.nix175
-rw-r--r--nixpkgs/nixos/modules/system/boot/resolved.nix5
-rw-r--r--nixpkgs/nixos/modules/virtualisation/docker-containers.nix13
-rw-r--r--nixpkgs/nixos/modules/virtualisation/virtualbox-host.nix2
-rw-r--r--nixpkgs/nixos/tests/all-tests.nix1
-rw-r--r--nixpkgs/nixos/tests/docker-tools.nix7
-rw-r--r--nixpkgs/nixos/tests/elk.nix61
-rw-r--r--nixpkgs/nixos/tests/gitea.nix2
-rw-r--r--nixpkgs/nixos/tests/hardened.nix37
-rw-r--r--nixpkgs/nixos/tests/paperless.nix29
-rw-r--r--nixpkgs/nixos/tests/virtualbox.nix42
-rw-r--r--nixpkgs/nixos/tests/xss-lock.nix36
36 files changed, 1055 insertions, 216 deletions
diff --git a/nixpkgs/nixos/modules/config/malloc.nix b/nixpkgs/nixos/modules/config/malloc.nix
new file mode 100644
index 000000000000..5fca39aa2e2a
--- /dev/null
+++ b/nixpkgs/nixos/modules/config/malloc.nix
@@ -0,0 +1,86 @@
+{ config, lib, pkgs, ... }:
+with lib;
+
+let
+  cfg = config.environment.memoryAllocator;
+
+  # The set of alternative malloc(3) providers.
+  providers = {
+    "graphene-hardened" = rec {
+      libPath = "${pkgs.graphene-hardened-malloc}/lib/libhardened_malloc.so";
+      description = ''
+        An allocator designed to mitigate memory corruption attacks, such as
+        those caused by use-after-free bugs.
+      '';
+    };
+
+    "jemalloc" = {
+      libPath = "${pkgs.jemalloc}/lib/libjemalloc.so";
+      description = ''
+        A general purpose allocator that emphasizes fragmentation avoidance
+        and scalable concurrency support.
+      '';
+    };
+  };
+
+  providerConf = providers."${cfg.provider}";
+
+  # An output that contains only the shared library, to avoid
+  # needlessly bloating the system closure
+  mallocLib = pkgs.runCommand "malloc-provider-${cfg.provider}"
+    rec {
+      preferLocalBuild = true;
+      allowSubstitutes = false;
+      origLibPath = providerConf.libPath;
+      libName = baseNameOf origLibPath;
+    }
+    ''
+      mkdir -p $out/lib
+      cp -L $origLibPath $out/lib/$libName
+    '';
+
+  # The full path to the selected provider shlib.
+  providerLibPath = "${mallocLib}/lib/${mallocLib.libName}";
+in
+
+{
+  meta = {
+    maintainers = [ maintainers.joachifm ];
+  };
+
+  options = {
+    environment.memoryAllocator.provider = mkOption {
+      type = types.enum ([ "libc" ] ++ attrNames providers);
+      default = "libc";
+      description = ''
+        The system-wide memory allocator.
+
+        Briefly, the system-wide memory allocator providers are:
+        <itemizedlist>
+        <listitem><para><literal>libc</literal>: the standard allocator provided by libc</para></listitem>
+        ${toString (mapAttrsToList
+            (name: value: "<listitem><para><literal>${name}</literal>: ${value.description}</para></listitem>")
+            providers)}
+        </itemizedlist>
+
+        <warning>
+        <para>
+        Selecting an alternative allocator (i.e., anything other than
+        <literal>libc</literal>) may result in instability, data loss,
+        and/or service failure.
+        </para>
+        </warning>
+
+        <note>
+        <para>
+        Changing this option does not affect the current session.
+        </para>
+        </note>
+      '';
+    };
+  };
+
+  config = mkIf (cfg.provider != "libc") {
+    environment.variables.LD_PRELOAD = providerLibPath;
+  };
+}
diff --git a/nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl b/nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl
index 686204ee0342..b7e5b99a9e01 100644
--- a/nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl
+++ b/nixpkgs/nixos/modules/installer/tools/nixos-generate-config.pl
@@ -464,6 +464,21 @@ EOF
     }
 }
 
+# For lack of a better way to determine it, guess whether we should use a
+# bigger font for the console from the display mode on the first
+# framebuffer. A way based on the physical size/actual DPI reported by
+# the monitor would be nice, but I don't know how to do this without X :)
+my $fb_modes_file = "/sys/class/graphics/fb0/modes";
+if (-f $fb_modes_file && -r $fb_modes_file) {
+    my $modes = read_file($fb_modes_file);
+    $modes =~ m/([0-9]+)x([0-9]+)/;
+    my $console_width = $1, my $console_height = $2;
+    if ($console_width > 1920) {
+        push @attrs, "# High-DPI console";
+        push @attrs, 'i18n.consoleFont = lib.mkDefault "${pkgs.terminus_font}/share/consolefonts/ter-u28n.psf.gz";';
+    }
+}
+
 
 # Generate the hardware configuration file.
 
diff --git a/nixpkgs/nixos/modules/misc/ids.nix b/nixpkgs/nixos/modules/misc/ids.nix
index f0c231a9d6f2..96ad4e904a49 100644
--- a/nixpkgs/nixos/modules/misc/ids.nix
+++ b/nixpkgs/nixos/modules/misc/ids.nix
@@ -339,6 +339,7 @@
       rss2email = 312;
       cockroachdb = 313;
       zoneminder = 314;
+      paperless = 315;
 
       # When adding a uid, make sure it doesn't match an existing gid. And don't use uids above 399!
 
@@ -638,6 +639,7 @@
       rss2email = 312;
       cockroachdb = 313;
       zoneminder = 314;
+      paperless = 315;
 
       # When adding a gid, make sure it doesn't match an existing
       # uid. Users and groups with the same name should have equal
diff --git a/nixpkgs/nixos/modules/module-list.nix b/nixpkgs/nixos/modules/module-list.nix
index 77b4ee82c4e6..089919d1d550 100644
--- a/nixpkgs/nixos/modules/module-list.nix
+++ b/nixpkgs/nixos/modules/module-list.nix
@@ -19,6 +19,7 @@
   ./config/iproute2.nix
   ./config/krb5/default.nix
   ./config/ldap.nix
+  ./config/malloc.nix
   ./config/networking.nix
   ./config/no-x-libs.nix
   ./config/nsswitch.nix
@@ -144,6 +145,7 @@
   ./programs/xonsh.nix
   ./programs/xss-lock.nix
   ./programs/yabar.nix
+  ./programs/zmap.nix
   ./programs/zsh/oh-my-zsh.nix
   ./programs/zsh/zsh.nix
   ./programs/zsh/zsh-autoenv.nix
@@ -436,6 +438,7 @@
   ./services/misc/octoprint.nix
   ./services/misc/osrm.nix
   ./services/misc/packagekit.nix
+  ./services/misc/paperless.nix
   ./services/misc/parsoid.nix
   ./services/misc/phd.nix
   ./services/misc/plex.nix
diff --git a/nixpkgs/nixos/modules/profiles/hardened.nix b/nixpkgs/nixos/modules/profiles/hardened.nix
index 9ab2ee87a19e..87bf66333c61 100644
--- a/nixpkgs/nixos/modules/profiles/hardened.nix
+++ b/nixpkgs/nixos/modules/profiles/hardened.nix
@@ -14,6 +14,8 @@ with lib;
 
   nix.allowedUsers = mkDefault [ "@users" ];
 
+  environment.memoryAllocator.provider = mkDefault "graphene-hardened";
+
   security.hideProcessInformation = mkDefault true;
 
   security.lockKernelModules = mkDefault true;
diff --git a/nixpkgs/nixos/modules/programs/xss-lock.nix b/nixpkgs/nixos/modules/programs/xss-lock.nix
index c290df01b960..070463311db5 100644
--- a/nixpkgs/nixos/modules/programs/xss-lock.nix
+++ b/nixpkgs/nixos/modules/programs/xss-lock.nix
@@ -8,12 +8,23 @@ in
 {
   options.programs.xss-lock = {
     enable = mkEnableOption "xss-lock";
+
     lockerCommand = mkOption {
       default = "${pkgs.i3lock}/bin/i3lock";
       example = literalExample ''''${pkgs.i3lock-fancy}/bin/i3lock-fancy'';
       type = types.string;
       description = "Locker to be used with xsslock";
     };
+
+    extraOptions = mkOption {
+      default = [ ];
+      example = [ "--ignore-sleep" ];
+      type = types.listOf types.str;
+      description = ''
+        Additional command-line arguments to pass to
+        <command>xss-lock</command>.
+      '';
+    };
   };
 
   config = mkIf cfg.enable {
@@ -21,7 +32,13 @@ in
       description = "XSS Lock Daemon";
       wantedBy = [ "graphical-session.target" ];
       partOf = [ "graphical-session.target" ];
-      serviceConfig.ExecStart = "${pkgs.xss-lock}/bin/xss-lock ${cfg.lockerCommand}";
+      serviceConfig.ExecStart = with lib;
+        strings.concatStringsSep " " ([
+            "${pkgs.xss-lock}/bin/xss-lock"
+          ] ++ (map escapeShellArg cfg.extraOptions) ++ [
+            "--"
+            cfg.lockerCommand
+        ]);
     };
   };
 }
diff --git a/nixpkgs/nixos/modules/programs/zmap.nix b/nixpkgs/nixos/modules/programs/zmap.nix
new file mode 100644
index 000000000000..2e27fce4d7c6
--- /dev/null
+++ b/nixpkgs/nixos/modules/programs/zmap.nix
@@ -0,0 +1,18 @@
+{ pkgs, config, lib, ... }:
+
+with lib;
+
+let
+  cfg = config.programs.zmap;
+in {
+  options.programs.zmap = {
+    enable = mkEnableOption "ZMap";
+  };
+
+  config = mkIf cfg.enable {
+    environment.systemPackages = [ pkgs.zmap ];
+
+    environment.etc."zmap/blacklist.conf".source = "${pkgs.zmap}/etc/zmap/blacklist.conf";
+    environment.etc."zmap/zmap.conf".source = "${pkgs.zmap}/etc/zmap.conf";
+  };
+}
diff --git a/nixpkgs/nixos/modules/rename.nix b/nixpkgs/nixos/modules/rename.nix
index 70807ccf7cd8..aa3d120c97f1 100644
--- a/nixpkgs/nixos/modules/rename.nix
+++ b/nixpkgs/nixos/modules/rename.nix
@@ -234,6 +234,9 @@ with lib;
     (mkRenamedOptionModule [ "hardware" "ckb" "enable" ] [ "hardware" "ckb-next" "enable" ])
     (mkRenamedOptionModule [ "hardware" "ckb" "package" ] [ "hardware" "ckb-next" "package" ])
 
+    # binfmt
+    (mkRenamedOptionModule [ "boot" "binfmtMiscRegistrations" ] [ "boot" "binfmt" "registrations" ])
+
   ] ++ (flip map [ "blackboxExporter" "collectdExporter" "fritzboxExporter"
                    "jsonExporter" "minioExporter" "nginxExporter" "nodeExporter"
                    "snmpExporter" "unifiExporter" "varnishExporter" ]
diff --git a/nixpkgs/nixos/modules/security/apparmor.nix b/nixpkgs/nixos/modules/security/apparmor.nix
index 4512a7a80f6d..cfc65b347bc6 100644
--- a/nixpkgs/nixos/modules/security/apparmor.nix
+++ b/nixpkgs/nixos/modules/security/apparmor.nix
@@ -29,6 +29,8 @@ in
    config = mkIf cfg.enable {
      environment.systemPackages = [ pkgs.apparmor-utils ];
 
+     boot.kernelParams = [ "apparmor=1" "security=apparmor" ];
+
      systemd.services.apparmor = let
        paths = concatMapStrings (s: " -I ${s}/etc/apparmor.d")
          ([ pkgs.apparmor-profiles ] ++ cfg.packages);
diff --git a/nixpkgs/nixos/modules/security/misc.nix b/nixpkgs/nixos/modules/security/misc.nix
index ecf22bf81c59..bf474ac0a546 100644
--- a/nixpkgs/nixos/modules/security/misc.nix
+++ b/nixpkgs/nixos/modules/security/misc.nix
@@ -13,23 +13,17 @@ with lib;
       default = true;
       description = ''
         Whether to allow creation of user namespaces.
-        </para>
 
-        <para>
         The motivation for disabling user namespaces is the potential
         presence of code paths where the kernel's permission checking
         logic fails to account for namespacing, instead permitting a
         namespaced process to act outside the namespace with the same
         privileges as it would have inside it.  This is particularly
         damaging in the common case of running as root within the namespace.
-        </para>
 
-        <para>
         When user namespace creation is disallowed, attempting to create a
         user namespace fails with "no space left on device" (ENOSPC).
         root may re-enable user namespace creation at runtime.
-        </para>
-        <para>
       '';
     };
 
@@ -48,21 +42,15 @@ with lib;
         Whether to allow SMT/hyperthreading.  Disabling SMT means that only
         physical CPU cores will be usable at runtime, potentially at
         significant performance cost.
-        </para>
 
-        <para>
         The primary motivation for disabling SMT is to mitigate the risk of
         leaking data between threads running on the same CPU core (due to
         e.g., shared caches).  This attack vector is unproven.
-        </para>
 
-        <para>
         Disabling SMT is a supplement to the L1 data cache flushing mitigation
         (see <xref linkend="opt-security.virtualization.flushL1DataCache"/>)
         versus malicious VM guests (SMT could "bring back" previously flushed
         data).
-        </para>
-        <para>
       '';
     };
 
@@ -73,10 +61,8 @@ with lib;
         Whether the hypervisor should flush the L1 data cache before
         entering guests.
         See also <xref linkend="opt-security.allowSimultaneousMultithreading"/>.
-        </para>
 
-        <para>
-          <variablelist>
+        <variablelist>
           <varlistentry>
             <term><literal>null</literal></term>
             <listitem><para>uses the kernel default</para></listitem>
@@ -98,7 +84,7 @@ with lib;
             enters the guest.  May incur significant performance cost.
             </para></listitem>
           </varlistentry>
-          </variablelist>
+        </variablelist>
       '';
     };
   };
diff --git a/nixpkgs/nixos/modules/security/rngd.nix b/nixpkgs/nixos/modules/security/rngd.nix
index a54ef2e6fcad..d9d6d9c9f253 100644
--- a/nixpkgs/nixos/modules/security/rngd.nix
+++ b/nixpkgs/nixos/modules/security/rngd.nix
@@ -2,20 +2,30 @@
 
 with lib;
 
+let
+  cfg = config.security.rngd;
+in
 {
   options = {
-    security.rngd.enable = mkOption {
-      type = types.bool;
-      default = true;
-      description = ''
-        Whether to enable the rng daemon, which adds entropy from
-        hardware sources of randomness to the kernel entropy pool when
-        available.
-      '';
+    security.rngd = {
+      enable = mkOption {
+        type = types.bool;
+        default = true;
+        description = ''
+          Whether to enable the rng daemon, which adds entropy from
+          hardware sources of randomness to the kernel entropy pool when
+          available.
+        '';
+      };
+      debug = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable debug output (-d).";
+      };
     };
   };
 
-  config = mkIf config.security.rngd.enable {
+  config = mkIf cfg.enable {
     services.udev.extraRules = ''
       KERNEL=="random", TAG+="systemd"
       SUBSYSTEM=="cpu", ENV{MODALIAS}=="cpu:type:x86,*feature:*009E*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="rngd.service"
@@ -29,7 +39,15 @@ with lib;
 
       description = "Hardware RNG Entropy Gatherer Daemon";
 
-      serviceConfig.ExecStart = "${pkgs.rng-tools}/sbin/rngd -f";
+      serviceConfig = {
+        ExecStart = "${pkgs.rng-tools}/sbin/rngd -f"
+          + optionalString cfg.debug " -d";
+        NoNewPrivileges = true;
+        PrivateNetwork = true;
+        PrivateTmp = true;
+        ProtectSystem = "full";
+        ProtectHome = true;
+      };
     };
   };
 }
diff --git a/nixpkgs/nixos/modules/services/backup/znapzend.nix b/nixpkgs/nixos/modules/services/backup/znapzend.nix
index 11b6215794ec..9c4c5545e35e 100644
--- a/nixpkgs/nixos/modules/services/backup/znapzend.nix
+++ b/nixpkgs/nixos/modules/services/backup/znapzend.nix
@@ -7,28 +7,23 @@ let
 
   planDescription = ''
       The znapzend backup plan to use for the source.
-    </para>
-    <para>
+
       The plan specifies how often to backup and for how long to keep the
       backups. It consists of a series of retention periodes to interval
       associations:
-    </para>
-    <para>
+
       <literal>
         retA=>intA,retB=>intB,...
       </literal>
-    </para>
-    <para>
-    Both intervals and retention periods are expressed in standard units
-    of time or multiples of them. You can use both the full name or a
-    shortcut according to the following listing:
-    </para>
-    <para>
+
+      Both intervals and retention periods are expressed in standard units
+      of time or multiples of them. You can use both the full name or a
+      shortcut according to the following listing:
+
       <literal>
         second|sec|s, minute|min, hour|h, day|d, week|w, month|mon|m, year|y
       </literal>
-    </para>
-    <para>
+
       See <citerefentry><refentrytitle>znapzendzetup</refentrytitle><manvolnum>1</manvolnum></citerefentry> for more info.
   '';
   planExample = "1h=>10min,1d=>1h,1w=>1d,1m=>1w,1y=>1m";
@@ -139,12 +134,10 @@ let
           type = nullOr ints.u16;
           description = ''
               Port to use for <command>mbuffer</command>.
-            </para>
-            <para>
+
               If this is null, it will run <command>mbuffer</command> through
               ssh.
-            </para>
-            <para>
+
               If this is not null, it will run <command>mbuffer</command>
               directly through TCP, which is not encrypted but faster. In that
               case the given port needs to be open on the destination host.
diff --git a/nixpkgs/nixos/modules/services/databases/foundationdb.nix b/nixpkgs/nixos/modules/services/databases/foundationdb.nix
index ad24f9f4b0fd..169ed37b348e 100644
--- a/nixpkgs/nixos/modules/services/databases/foundationdb.nix
+++ b/nixpkgs/nixos/modules/services/databases/foundationdb.nix
@@ -35,6 +35,7 @@ let
     ${optionalString (cfg.class != null) "class = ${cfg.class}"}
     memory         = ${cfg.memory}
     storage_memory = ${cfg.storageMemory}
+    trace_format   = ${cfg.traceFormat}
 
     ${optionalString (cfg.tls != null) ''
       tls_plugin           = ${pkg}/libexec/plugins/FDBLibTLS.so
@@ -317,6 +318,12 @@ in
       default     = "/run/foundationdb.pid";
       description = "Path to pidfile for fdbmonitor.";
     };
+
+    traceFormat = mkOption {
+      type = types.enum [ "xml" "json" ];
+      default = "xml";
+      description = "Trace logging format.";
+    };
   };
 
   config = mkIf cfg.enable {
@@ -382,7 +389,7 @@ in
           chown -R ${cfg.user}:${cfg.group} ${cfg.pidfile}
 
         for x in "${cfg.logDir}" "${cfg.dataDir}"; do
-          [ ! -d "$x" ] && mkdir -m 0700 -vp "$x";
+          [ ! -d "$x" ] && mkdir -m 0770 -vp "$x";
           chown -R ${cfg.user}:${cfg.group} "$x";
         done
 
@@ -404,7 +411,7 @@ in
 
       postStart = ''
         if [ -e "${cfg.dataDir}/.first_startup" ]; then
-          fdbcli --exec "configure new single memory"
+          fdbcli --exec "configure new single ssd"
           rm -f "${cfg.dataDir}/.first_startup";
         fi
       '';
diff --git a/nixpkgs/nixos/modules/services/logging/journalbeat.nix b/nixpkgs/nixos/modules/services/logging/journalbeat.nix
index 8186a3b02c37..89f53b1b2454 100644
--- a/nixpkgs/nixos/modules/services/logging/journalbeat.nix
+++ b/nixpkgs/nixos/modules/services/logging/journalbeat.nix
@@ -5,11 +5,13 @@ with lib;
 let
   cfg = config.services.journalbeat;
 
+  lt6 = builtins.compareVersions cfg.package.version "6" < 0;
+
   journalbeatYml = pkgs.writeText "journalbeat.yml" ''
     name: ${cfg.name}
     tags: ${builtins.toJSON cfg.tags}
 
-    journalbeat.cursor_state_file: ${cfg.stateDir}/cursor-state
+    ${optionalString lt6 "journalbeat.cursor_state_file: /var/lib/${cfg.stateDir}/cursor-state"}
 
     ${cfg.extraConfig}
   '';
@@ -22,6 +24,16 @@ in
 
       enable = mkEnableOption "journalbeat";
 
+      package = mkOption {
+        type = types.package;
+        default = pkgs.journalbeat;
+        defaultText = "pkgs.journalbeat";
+        example = literalExample "pkgs.journalbeat7";
+        description = ''
+          The journalbeat package to use
+        '';
+      };
+
       name = mkOption {
         type = types.str;
         default = "journalbeat";
@@ -36,13 +48,17 @@ in
 
       stateDir = mkOption {
         type = types.str;
-        default = "/var/lib/journalbeat";
-        description = "The state directory. Journalbeat's own logs and other data are stored here.";
+        default = "journalbeat";
+        description = ''
+          Directory below <literal>/var/lib/</literal> to store journalbeat's
+          own logs and other data. This directory will be created automatically
+          using systemd's StateDirectory mechanism.
+        '';
       };
 
       extraConfig = mkOption {
         type = types.lines;
-        default = ''
+        default = optionalString lt6 ''
           journalbeat:
             seek_position: cursor
             cursor_seek_fallback: tail
@@ -61,7 +77,16 @@ in
 
   config = mkIf cfg.enable {
 
-    systemd.services.journalbeat = with pkgs; {
+    assertions = [
+      {
+        assertion = !hasPrefix "/" cfg.stateDir;
+        message =
+          "The option services.journalbeat.stateDir shouldn't be an absolute directory." +
+          " It should be a directory relative to /var/lib/.";
+      }
+    ];
+
+    systemd.services.journalbeat = {
       description = "Journalbeat log shipper";
       wantedBy = [ "multi-user.target" ];
       preStart = ''
@@ -69,7 +94,13 @@ in
         mkdir -p ${cfg.stateDir}/logs
       '';
       serviceConfig = {
-        ExecStart = "${pkgs.journalbeat}/bin/journalbeat -c ${journalbeatYml} -path.data ${cfg.stateDir}/data -path.logs ${cfg.stateDir}/logs";
+        StateDirectory = cfg.stateDir;
+        ExecStart = ''
+          ${cfg.package}/bin/journalbeat \
+            -c ${journalbeatYml} \
+            -path.data /var/lib/${cfg.stateDir}/data \
+            -path.logs /var/lib/${cfg.stateDir}/logs'';
+        Restart = "always";
       };
     };
   };
diff --git a/nixpkgs/nixos/modules/services/misc/jellyfin.nix b/nixpkgs/nixos/modules/services/misc/jellyfin.nix
index 7f38dd0ff233..55559206568d 100644
--- a/nixpkgs/nixos/modules/services/misc/jellyfin.nix
+++ b/nixpkgs/nixos/modules/services/misc/jellyfin.nix
@@ -48,12 +48,6 @@ in
       jellyfin = {};
     };
 
-    assertions = [
-      {
-        assertion = !config.services.emby.enable;
-        message = "Emby and Jellyfin are incompatible, you cannot enable both";
-      }
-    ];
   };
 
   meta.maintainers = with lib.maintainers; [ minijackson ];
diff --git a/nixpkgs/nixos/modules/services/misc/paperless.nix b/nixpkgs/nixos/modules/services/misc/paperless.nix
new file mode 100644
index 000000000000..4e6cd80e2425
--- /dev/null
+++ b/nixpkgs/nixos/modules/services/misc/paperless.nix
@@ -0,0 +1,185 @@
+{ config, pkgs, lib, ... }:
+
+with lib;
+let
+  cfg = config.services.paperless;
+
+  defaultUser = "paperless";
+
+  manage = cfg.package.withConfig {
+    config = {
+      PAPERLESS_CONSUMPTION_DIR = cfg.consumptionDir;
+      PAPERLESS_INLINE_DOC = "true";
+      PAPERLESS_DISABLE_LOGIN = "true";
+    } // cfg.extraConfig;
+    inherit (cfg) dataDir ocrLanguages;
+    paperlessPkg = cfg.package;
+  };
+in
+{
+  options.services.paperless = {
+    enable = mkOption {
+      type = lib.types.bool;
+      default = false;
+      description = ''
+        Enable Paperless.
+
+        When started, the Paperless database is automatically created if it doesn't
+        exist and updated if the Paperless package has changed.
+        Both tasks are achieved by running a Django migration.
+      '';
+    };
+
+    dataDir = mkOption {
+      type = types.str;
+      default = "/var/lib/paperless";
+      description = "Directory to store the Paperless data.";
+    };
+
+    consumptionDir = mkOption {
+      type = types.str;
+      default = "${cfg.dataDir}/consume";
+      defaultText = "\${dataDir}/consume";
+      description = "Directory from which new documents are imported.";
+    };
+
+    consumptionDirIsPublic = mkOption {
+      type = types.bool;
+      default = false;
+      description = "Whether all users can write to the consumption dir.";
+    };
+
+    ocrLanguages = mkOption {
+      type = with types; nullOr (listOf string);
+      default = null;
+      description = ''
+        Languages available for OCR via Tesseract, specified as
+        <literal>ISO 639-2/T</literal> language codes.
+        If unset, defaults to all available languages.
+      '';
+      example = [ "eng" "spa" "jpn" ];
+    };
+
+    address = mkOption {
+      type = types.str;
+      default = "localhost";
+      description = "Server listening address.";
+    };
+
+    port = mkOption {
+      type = types.int;
+      default = 28981;
+      description = "Server port to listen on.";
+    };
+
+    extraConfig = mkOption {
+      type = types.attrs;
+      default = {};
+      description = ''
+        Extra paperless config options.
+
+        The config values are evaluated as double-quoted Bash string literals.
+
+        See <literal>paperless-src/paperless.conf.example</literal> for available options.
+
+        To enable user authentication, set <literal>PAPERLESS_DISABLE_LOGIN = "false"</literal>
+        and run the shell command <literal>$dataDir/paperless-manage createsuperuser</literal>.
+
+        To define secret options without storing them in /nix/store, use the following pattern:
+        <literal>PAPERLESS_PASSPHRASE = "$(&lt; /etc/my_passphrase_file)"</literal>
+      '';
+      example = literalExample ''
+        {
+          PAPERLESS_OCR_LANGUAGE = "deu";
+        }
+      '';
+    };
+
+    user = mkOption {
+      type = types.str;
+      default = defaultUser;
+      description = "User under which Paperless runs.";
+    };
+
+    package = mkOption {
+      type = types.package;
+      default = pkgs.paperless;
+      defaultText = "pkgs.paperless";
+      description = "The Paperless package to use.";
+    };
+
+    manage = mkOption {
+      type = types.package;
+      readOnly = true;
+      default = manage;
+      description = ''
+        A script to manage the Paperless instance.
+        It wraps Django's manage.py and is also available at
+        <literal>$dataDir/manage-paperless</literal>
+      '';
+    };
+  };
+
+  config = mkIf cfg.enable {
+
+    systemd.tmpfiles.rules = [
+      "d '${cfg.dataDir}' - ${cfg.user} ${cfg.user} - -"
+    ] ++ (optional cfg.consumptionDirIsPublic
+      "d '${cfg.consumptionDir}' 777 ${cfg.user} ${cfg.user} - -"
+      # If the consumption dir is not created here, it's automatically created by
+      # 'manage' with the default permissions.
+    );
+
+    systemd.services.paperless-consumer = {
+      description = "Paperless document consumer";
+      serviceConfig = {
+        User = cfg.user;
+        ExecStart = "${manage} document_consumer";
+        Restart = "always";
+      };
+      after = [ "systemd-tmpfiles-setup.service" ];
+      wantedBy = [ "multi-user.target" ];
+      preStart = ''
+        if [[ $(readlink ${cfg.dataDir}/paperless-manage) != ${manage} ]]; then
+          ln -sf ${manage} ${cfg.dataDir}/paperless-manage
+        fi
+
+        ${manage.setupEnv}
+        # Auto-migrate on first run or if the package has changed
+        versionFile="$PAPERLESS_DBDIR/src-version"
+        if [[ $(cat "$versionFile" 2>/dev/null) != ${cfg.package} ]]; then
+          python $paperlessSrc/manage.py migrate
+          echo ${cfg.package} > "$versionFile"
+        fi
+      '';
+    };
+
+    systemd.services.paperless-server = {
+      description = "Paperless document server";
+      serviceConfig = {
+        User = cfg.user;
+        ExecStart = "${manage} runserver --noreload ${cfg.address}:${toString cfg.port}";
+        Restart = "always";
+      };
+      # Bind to `paperless-consumer` so that the server never runs
+      # during migrations
+      bindsTo = [ "paperless-consumer.service" ];
+      after = [ "paperless-consumer.service" ];
+      wantedBy = [ "multi-user.target" ];
+    };
+
+    users = optionalAttrs (cfg.user == defaultUser) {
+      users = [{
+        name = defaultUser;
+        group = defaultUser;
+        uid = config.ids.uids.paperless;
+        home = cfg.dataDir;
+      }];
+
+      groups = [{
+        name = defaultUser;
+        gid = config.ids.gids.paperless;
+      }];
+    };
+  };
+}
diff --git a/nixpkgs/nixos/modules/services/monitoring/vnstat.nix b/nixpkgs/nixos/modules/services/monitoring/vnstat.nix
index cb2f8c07edb9..e9bedb704a43 100644
--- a/nixpkgs/nixos/modules/services/monitoring/vnstat.nix
+++ b/nixpkgs/nixos/modules/services/monitoring/vnstat.nix
@@ -28,14 +28,29 @@ in {
       path = [ pkgs.coreutils ];
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
-      unitConfig.documentation = "man:vnstatd(1) man:vnstat(1) man:vnstat.conf(5)";
+      documentation = [
+        "man:vnstatd(1)"
+        "man:vnstat(1)"
+        "man:vnstat.conf(5)"
+      ];
       preStart = "chmod 755 /var/lib/vnstat";
       serviceConfig = {
         ExecStart = "${pkgs.vnstat}/bin/vnstatd -n";
         ExecReload = "${pkgs.procps}/bin/kill -HUP $MAINPID";
-        ProtectHome = true;
+
+        # Hardening (from upstream example service)
+        ProtectSystem = "strict";
+        StateDirectory = "vnstat";
         PrivateDevices = true;
+        ProtectKernelTunables = true;
+        ProtectControlGroups = true;
+        ProtectHome = true;
+        ProtectKernelModules = true;
         PrivateTmp = true;
+        MemoryDenyWriteExecute = true;
+        RestrictRealtime = true;
+        RestrictNamespaces = true;
+
         User = "vnstatd";
       };
     };
diff --git a/nixpkgs/nixos/modules/services/networking/tinc.nix b/nixpkgs/nixos/modules/services/networking/tinc.nix
index 3379efd1afce..e98aafc20937 100644
--- a/nixpkgs/nixos/modules/services/networking/tinc.nix
+++ b/nixpkgs/nixos/modules/services/networking/tinc.nix
@@ -153,7 +153,6 @@ in
       ({
         description = "Tinc Daemon - ${network}";
         wantedBy = [ "multi-user.target" ];
-        after = [ "network.target" ];
         path = [ data.package ];
         restartTriggers = [ config.environment.etc."tinc/${network}/tinc.conf".source ];
         serviceConfig = {
diff --git a/nixpkgs/nixos/modules/services/security/fprintd.nix b/nixpkgs/nixos/modules/services/security/fprintd.nix
index a35b065ba815..9ed7f2a2efd9 100644
--- a/nixpkgs/nixos/modules/services/security/fprintd.nix
+++ b/nixpkgs/nixos/modules/services/security/fprintd.nix
@@ -26,28 +26,20 @@ in
       };
 
     };
-    
+
   };
-  
-  
+
+
   ###### implementation
-  
+
   config = mkIf cfg.enable {
 
     services.dbus.packages = [ pkgs.fprintd ];
 
     environment.systemPackages = [ pkgs.fprintd ];
 
-    systemd.services.fprintd = {
-      description = "Fingerprint Authentication Daemon";
-
-      serviceConfig = {
-        Type = "dbus";
-        BusName = "net.reactivated.Fprint";
-        ExecStart = "${pkgs.fprintd}/libexec/fprintd";
-      };
-    };
+    systemd.packages = [ pkgs.fprintd ];
 
   };
-  
+
 }
diff --git a/nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix b/nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix
index 3ab4f26399f3..afa0cebbc527 100644
--- a/nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix
+++ b/nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -189,6 +189,11 @@ in
   config = mkIf cfg.enable {
 
     assertions = [
+      { assertion = xcfg.enable;
+        message = ''
+          LightDM requires services.xserver.enable to be true
+        '';
+      }
       { assertion = cfg.autoLogin.enable -> cfg.autoLogin.user != null;
         message = ''
           LightDM auto-login requires services.xserver.displayManager.lightdm.autoLogin.user to be set
diff --git a/nixpkgs/nixos/modules/services/x11/display-managers/sddm.nix b/nixpkgs/nixos/modules/services/x11/display-managers/sddm.nix
index 05830e325d51..d1ed345ac579 100644
--- a/nixpkgs/nixos/modules/services/x11/display-managers/sddm.nix
+++ b/nixpkgs/nixos/modules/services/x11/display-managers/sddm.nix
@@ -195,6 +195,11 @@ in
   config = mkIf cfg.enable {
 
     assertions = [
+      { assertion = xcfg.enable;
+        message = ''
+          SDDM requires services.xserver.enable to be true
+        '';
+      }
       { assertion = cfg.autoLogin.enable -> cfg.autoLogin.user != null;
         message = ''
           SDDM auto-login requires services.xserver.displayManager.sddm.autoLogin.user to be set
@@ -264,8 +269,8 @@ in
     };
 
     environment.etc."sddm.conf".source = cfgFile;
-    environment.pathsToLink = [ 
-      "/share/sddm" 
+    environment.pathsToLink = [
+      "/share/sddm"
     ];
 
     users.groups.sddm.gid = config.ids.gids.sddm;
diff --git a/nixpkgs/nixos/modules/system/boot/binfmt.nix b/nixpkgs/nixos/modules/system/boot/binfmt.nix
index 15e84dc021e2..d6c0f0504868 100644
--- a/nixpkgs/nixos/modules/system/boot/binfmt.nix
+++ b/nixpkgs/nixos/modules/system/boot/binfmt.nix
@@ -1,8 +1,8 @@
-{ config, lib, ... }:
+{ config, lib, pkgs, ... }:
 let
   inherit (lib) mkOption types optionalString;
 
-  cfg = config.boot.binfmtMiscRegistrations;
+  cfg = config.boot.binfmt;
 
   makeBinfmtLine = name: { recognitionType, offset, magicOrExtension
                          , mask, preserveArgvZero, openBinary
@@ -13,125 +13,249 @@ let
     mask' = toString mask;
     interpreter = "/run/binfmt/${name}";
     flags = if !(matchCredentials -> openBinary)
-              then throw "boot.binfmtMiscRegistrations.${name}: you can't specify openBinary = false when matchCredentials = true."
+              then throw "boot.binfmt.registrations.${name}: you can't specify openBinary = false when matchCredentials = true."
             else optionalString preserveArgvZero "P" +
                  optionalString (openBinary && !matchCredentials) "O" +
                  optionalString matchCredentials "C" +
                  optionalString fixBinary "F";
   in ":${name}:${type}:${offset'}:${magicOrExtension}:${mask'}:${interpreter}:${flags}";
 
-  binfmtFile = builtins.toFile "binfmt_nixos.conf"
-    (lib.concatStringsSep "\n" (lib.mapAttrsToList makeBinfmtLine cfg));
-
   activationSnippet = name: { interpreter, ... }:
     "ln -sf ${interpreter} /run/binfmt/${name}";
-  activationScript = ''
-    mkdir -p -m 0755 /run/binfmt
-    ${lib.concatStringsSep "\n" (lib.mapAttrsToList activationSnippet cfg)}
-  '';
+
+  getEmulator = system: (lib.systems.elaborate { inherit system; }).emulator pkgs;
+
+  # Mapping of systems to “magicOrExtension” and “mask”. Mostly taken from:
+  # - https://github.com/cleverca22/nixos-configs/blob/master/qemu.nix
+  # and
+  # - https://github.com/qemu/qemu/blob/master/scripts/qemu-binfmt-conf.sh
+  # TODO: maybe put these in a JSON file?
+  magics = {
+    armv6l-linux = {
+      magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00'';
+      mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\x00\xff\xfe\xff\xff\xff'';
+    };
+    armv7l-linux = {
+      magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00'';
+      mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\x00\xff\xfe\xff\xff\xff'';
+    };
+    aarch64-linux = {
+      magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00'';
+      mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\x00\xff\xfe\xff\xff\xff'';
+    };
+    aarch64_be-linux = {
+      magicOrExtension = ''\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7'';
+      mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
+    };
+    i386-linux = {
+      magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00'';
+      mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
+    };
+    i486-linux = {
+      magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00'';
+      mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
+    };
+    i586-linux = {
+      magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00'';
+      mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
+    };
+    i686-linux = {
+      magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00'';
+      mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
+    };
+    x86_64-linux = {
+      magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00'';
+      mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
+    };
+    alpha-linux = {
+      magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x26\x90'';
+      mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
+    };
+    sparc64-linux = {
+      magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02'';
+      mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
+    };
+    sparc-linux = {
+      magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x12'';
+      mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
+    };
+    powerpc-linux = {
+      magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14'';
+      mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
+    };
+    powerpc64-linux = {
+      magicOrExtension = ''\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15'';
+      mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
+    };
+    powerpc64le-linux = {
+      magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15\x00'';
+      mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\x00'';
+    };
+    mips-linux = {
+      magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08'';
+      mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
+    };
+    mipsel-linux = {
+      magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00'';
+      mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
+    };
+    mips64-linux = {
+      magicOrExtension = ''\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08'';
+      mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
+    };
+    mips64el-linux = {
+      magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00'';
+      mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
+    };
+    riscv32-linux = {
+      magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00'';
+      mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
+    };
+    riscv64-linux = {
+      magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00'';
+      mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
+    };
+    x86_64-windows = {
+      magicOrExtension = ".exe";
+      recognitionType = "extension";
+    };
+    i686-windows = {
+      magicOrExtension = ".exe";
+      recognitionType = "extension";
+    };
+  };
+
 in {
   options = {
-    boot.binfmtMiscRegistrations = mkOption {
-      default = {};
-
-      description = ''
-        Extra binary formats to register with the kernel.
-        See https://www.kernel.org/doc/html/latest/admin-guide/binfmt-misc.html for more details.
-      '';
-
-      type = types.attrsOf (types.submodule ({ config, ... }: {
-        options = {
-          recognitionType = mkOption {
-            default = "magic";
-            description = "Whether to recognize executables by magic number or extension.";
-            type = types.enum [ "magic" "extension" ];
-          };
+    boot.binfmt = {
+      registrations = mkOption {
+        default = {};
 
-          offset = mkOption {
-            default = null;
-            description = "The byte offset of the magic number used for recognition.";
-            type = types.nullOr types.int;
-          };
+        description = ''
+          Extra binary formats to register with the kernel.
+          See https://www.kernel.org/doc/html/latest/admin-guide/binfmt-misc.html for more details.
+        '';
 
-          magicOrExtension = mkOption {
-            description = "The magic number or extension to match on.";
-            type = types.str;
-          };
+        type = types.attrsOf (types.submodule ({ config, ... }: {
+          options = {
+            recognitionType = mkOption {
+              default = "magic";
+              description = "Whether to recognize executables by magic number or extension.";
+              type = types.enum [ "magic" "extension" ];
+            };
 
-          mask = mkOption {
-            default = null;
-            description =
-              "A mask to be ANDed with the byte sequence of the file before matching";
-            type = types.nullOr types.str;
-          };
+            offset = mkOption {
+              default = null;
+              description = "The byte offset of the magic number used for recognition.";
+              type = types.nullOr types.int;
+            };
 
-          interpreter = mkOption {
-            description = ''
-              The interpreter to invoke to run the program.
+            magicOrExtension = mkOption {
+              description = "The magic number or extension to match on.";
+              type = types.str;
+            };
 
-              Note that the actual registration will point to
-              /run/binfmt/''${name}, so the kernel interpreter length
-              limit doesn't apply.
-            '';
-            type = types.path;
-          };
+            mask = mkOption {
+              default = null;
+              description =
+                "A mask to be ANDed with the byte sequence of the file before matching";
+              type = types.nullOr types.str;
+            };
 
-          preserveArgvZero = mkOption {
-            default = false;
-            description = ''
-              Whether to pass the original argv[0] to the interpreter.
+            interpreter = mkOption {
+              description = ''
+                The interpreter to invoke to run the program.
 
-              See the description of the 'P' flag in the kernel docs
-              for more details;
-            '';
-            type = types.bool;
-          };
+                Note that the actual registration will point to
+                /run/binfmt/''${name}, so the kernel interpreter length
+                limit doesn't apply.
+              '';
+              type = types.path;
+            };
 
-          openBinary = mkOption {
-            default = config.matchCredentials;
-            description = ''
-              Whether to pass the binary to the interpreter as an open
-              file descriptor, instead of a path.
-            '';
-            type = types.bool;
-          };
+            preserveArgvZero = mkOption {
+              default = false;
+              description = ''
+                Whether to pass the original argv[0] to the interpreter.
 
-          matchCredentials = mkOption {
-            default = false;
-            description = ''
-              Whether to launch with the credentials and security
-              token of the binary, not the interpreter (e.g. setuid
-              bit).
+                See the description of the 'P' flag in the kernel docs
+                for more details;
+              '';
+              type = types.bool;
+            };
 
-              See the description of the 'C' flag in the kernel docs
-              for more details.
+            openBinary = mkOption {
+              default = config.matchCredentials;
+              description = ''
+                Whether to pass the binary to the interpreter as an open
+                file descriptor, instead of a path.
+              '';
+              type = types.bool;
+            };
 
-              Implies/requires openBinary = true.
-            '';
-            type = types.bool;
-          };
+            matchCredentials = mkOption {
+              default = false;
+              description = ''
+                Whether to launch with the credentials and security
+                token of the binary, not the interpreter (e.g. setuid
+                bit).
 
-          fixBinary = mkOption {
-            default = false;
-            description = ''
-              Whether to open the interpreter file as soon as the
-              registration is loaded, rather than waiting for a
-              relevant file to be invoked.
-
-              See the description of the 'F' flag in the kernel docs
-              for more details.
-            '';
-            type = types.bool;
+                See the description of the 'C' flag in the kernel docs
+                for more details.
+
+                Implies/requires openBinary = true.
+              '';
+              type = types.bool;
+            };
+
+            fixBinary = mkOption {
+              default = false;
+              description = ''
+                Whether to open the interpreter file as soon as the
+                registration is loaded, rather than waiting for a
+                relevant file to be invoked.
+
+                See the description of the 'F' flag in the kernel docs
+                for more details.
+              '';
+              type = types.bool;
+            };
           };
-        };
-      }));
+        }));
+      };
+
+      emulatedSystems = mkOption {
+        default = [];
+        description = ''
+          List of systems to emulate. Will also configure Nix to
+          support your new systems.
+        '';
+        type = types.listOf types.string;
+      };
     };
   };
 
-  config = lib.mkIf (cfg != {}) {
-    environment.etc."binfmt.d/nixos.conf".source = binfmtFile;
-    system.activationScripts.binfmt = activationScript;
-    systemd.additionalUpstreamSystemUnits =
+  config = {
+    boot.binfmt.registrations = builtins.listToAttrs (map (system: {
+      name = system;
+      value = {
+        interpreter = getEmulator system;
+      } // (magics.${system} or (throw "Cannot create binfmt registration for system ${system}"));
+    }) cfg.emulatedSystems);
+    # TODO: add a nix.extraPlatforms option to NixOS!
+    nix.extraOptions = lib.mkIf (cfg.emulatedSystems != []) ''
+      extra-platforms = ${toString (cfg.emulatedSystems ++ lib.optional pkgs.stdenv.hostPlatform.isx86_64 "i686-linux")}
+    '';
+    nix.sandboxPaths = lib.mkIf (cfg.emulatedSystems != [])
+      ([ "/run/binfmt" ] ++ (map (system: dirOf (dirOf (getEmulator system))) cfg.emulatedSystems));
+
+    environment.etc."binfmt.d/nixos.conf".source = builtins.toFile "binfmt_nixos.conf"
+      (lib.concatStringsSep "\n" (lib.mapAttrsToList makeBinfmtLine config.boot.binfmt.registrations));
+    system.activationScripts.binfmt = ''
+      mkdir -p -m 0755 /run/binfmt
+      ${lib.concatStringsSep "\n" (lib.mapAttrsToList activationSnippet config.boot.binfmt.registrations)}
+    '';
+    systemd.additionalUpstreamSystemUnits = lib.mkIf (config.boot.binfmt.registrations != {})
       [ "proc-sys-fs-binfmt_misc.automount"
         "proc-sys-fs-binfmt_misc.mount"
       ];
diff --git a/nixpkgs/nixos/modules/system/boot/kexec.nix b/nixpkgs/nixos/modules/system/boot/kexec.nix
index 61f9c6d0e7eb..fd2cb94b756b 100644
--- a/nixpkgs/nixos/modules/system/boot/kexec.nix
+++ b/nixpkgs/nixos/modules/system/boot/kexec.nix
@@ -13,8 +13,18 @@
         path = [ pkgs.kexectools ];
         script =
           ''
+            # Don't load the current system profile if we already have a kernel loaded
+            if [[ 1 = "$(</sys/kernel/kexec_loaded)" ]] ; then
+              echo "kexec kernel has already been loaded, prepare-kexec skipped"
+              exit 0
+            fi
+
             p=$(readlink -f /nix/var/nix/profiles/system)
-            if ! [ -d $p ]; then exit 1; fi
+            if ! [[ -d $p ]]; then
+              echo "Could not find system profile for prepare-kexec"
+              exit 1
+            fi
+            echo "Loading NixOS system via kexec."
             exec kexec --load $p/kernel --initrd=$p/initrd --append="$(cat $p/kernel-params) init=$p/init"
           '';
       };
diff --git a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
index 9ad2a2779e18..03a5fece82ee 100644
--- a/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
+++ b/nixpkgs/nixos/modules/system/boot/loader/systemd-boot/systemd-boot.nix
@@ -62,8 +62,7 @@ in {
 
       description = ''
         The resolution of the console. The following values are valid:
-        </para>
-        <para>
+
         <itemizedlist>
           <listitem><para>
             <literal>"0"</literal>: Standard UEFI 80x25 mode
diff --git a/nixpkgs/nixos/modules/system/boot/luksroot.nix b/nixpkgs/nixos/modules/system/boot/luksroot.nix
index 3841074f0433..9dcb683eff43 100644
--- a/nixpkgs/nixos/modules/system/boot/luksroot.nix
+++ b/nixpkgs/nixos/modules/system/boot/luksroot.nix
@@ -76,6 +76,33 @@ let
         fi
         return 0
     }
+
+    wait_gpgcard() {
+        local secs="''${1:-10}"
+
+        gpg --card-status > /dev/null 2> /dev/null
+        if [ $? != 0 ]; then
+            echo -n "Waiting $secs seconds for GPG Card to appear"
+            local success=false
+            for try in $(seq $secs); do
+                echo -n .
+                sleep 1
+                gpg --card-status > /dev/null 2> /dev/null
+                if [ $? == 0 ]; then
+                    success=true
+                    break
+                fi
+            done
+            if [ $success == true ]; then
+                echo " - success";
+                return 0
+            else
+                echo " - failure";
+                return 1
+            fi
+        fi
+        return 0
+    }
   '';
 
   preCommands = ''
@@ -93,6 +120,13 @@ let
     # For Yubikey salt storage
     mkdir -p /crypt-storage
 
+    ${optionalString luks.gpgSupport ''
+    export GPG_TTY=$(tty)
+    export GNUPGHOME=/crypt-ramfs/.gnupg
+
+    gpg-agent --daemon --scdaemon-program $out/bin/scdaemon > /dev/null 2> /dev/null
+    ''}
+        
     # Disable all input echo for the whole stage. We could use read -s
     # instead but that would ocasionally leak characters between read
     # invocations.
@@ -105,7 +139,7 @@ let
     umount /crypt-ramfs 2>/dev/null
   '';
 
-  openCommand = name': { name, device, header, keyFile, keyFileSize, keyFileOffset, allowDiscards, yubikey, fallbackToPassword, ... }: assert name' == name;
+  openCommand = name': { name, device, header, keyFile, keyFileSize, keyFileOffset, allowDiscards, yubikey, gpgCard, fallbackToPassword, ... }: assert name' == name;
   let
     csopen   = "cryptsetup luksOpen ${device} ${name} ${optionalString allowDiscards "--allow-discards"} ${optionalString (header != null) "--header=${header}"}";
     cschange = "cryptsetup luksChangeKey ${device} ${optionalString (header != null) "--header=${header}"}";
@@ -182,7 +216,7 @@ let
         ''}
     }
 
-    ${if luks.yubikeySupport && (yubikey != null) then ''
+    ${optionalString (luks.yubikeySupport && (yubikey != null)) ''
     # Yubikey
     rbtohex() {
         ( od -An -vtx1 | tr -d ' \n' )
@@ -278,7 +312,7 @@ let
         umount /crypt-storage
     }
 
-    open_yubikey() {
+    open_with_hardware() {
         if wait_yubikey ${toString yubikey.gracePeriod}; then
             do_open_yubikey
         else
@@ -286,8 +320,75 @@ let
             open_normally
         fi
     }
+    ''}
 
-    open_yubikey
+    ${optionalString (luks.gpgSupport && (gpgCard != null)) ''
+
+    do_open_gpg_card() {
+        # Make all of these local to this function
+        # to prevent their values being leaked
+        local pin
+        local opened
+
+        gpg --import /gpg-keys/${device}/pubkey.asc > /dev/null 2> /dev/null
+
+        gpg --card-status > /dev/null 2> /dev/null
+
+        for try in $(seq 3); do
+            echo -n "PIN for GPG Card associated with device ${device}: "
+            pin=
+            while true; do
+                if [ -e /crypt-ramfs/passphrase ]; then
+                    echo "reused"
+                    pin=$(cat /crypt-ramfs/passphrase)
+                    break
+                else
+                    # and try reading it from /dev/console with a timeout
+                    IFS= read -t 1 -r pin
+                    if [ -n "$pin" ]; then
+                       ${if luks.reusePassphrases then ''
+                         # remember it for the next device
+                         echo -n "$pin" > /crypt-ramfs/passphrase
+                       '' else ''
+                         # Don't save it to ramfs. We are very paranoid
+                       ''}
+                       echo
+                       break
+                    fi
+                fi
+            done
+            echo -n "Verifying passphrase for ${device}..."
+            echo -n "$pin" | gpg -q --batch --passphrase-fd 0 --pinentry-mode loopback -d /gpg-keys/${device}/cryptkey.gpg 2> /dev/null | ${csopen} --key-file=- > /dev/null 2> /dev/null
+            if [ $? == 0 ]; then
+                echo " - success"
+                ${if luks.reusePassphrases then ''
+                  # we don't rm here because we might reuse it for the next device
+                '' else ''
+                  rm -f /crypt-ramfs/passphrase
+                ''}
+                break
+            else
+                echo " - failure"
+                # ask for a different one
+                rm -f /crypt-ramfs/passphrase
+            fi
+        done
+
+        [ "$opened" == false ] && die "Maximum authentication errors reached"
+    }
+
+    open_with_hardware() {
+        if wait_gpgcard ${toString gpgCard.gracePeriod}; then
+            do_open_gpg_card
+        else
+            echo "No GPG Card found, falling back to normal open procedure"
+            open_normally
+        fi
+    }
+    ''}
+
+    ${if (luks.yubikeySupport && (yubikey != null)) || (luks.gpgSupport && (gpgCard != null)) then ''
+    open_with_hardware
     '' else ''
     open_normally
     ''}
@@ -473,6 +574,36 @@ in
             '';
           };
 
+          gpgCard = mkOption {
+            default = null;
+            description = ''
+              The option to use this LUKS device with a GPG encrypted luks password by the GPG Smartcard.
+              If null (the default), GPG-Smartcard will be disabled for this device.
+            '';
+
+            type = with types; nullOr (submodule {
+              options = {
+                gracePeriod = mkOption {
+                  default = 10;
+                  type = types.int;
+                  description = "Time in seconds to wait for the GPG Smartcard.";
+                };
+
+                encryptedPass = mkOption {
+                  default = "";
+                  type = types.path;
+                  description = "Path to the GPG encrypted passphrase.";
+                };
+
+                publicKey = mkOption {
+                  default = "";
+                  type = types.path;
+                  description = "Path to the Public Key.";
+                };
+              };
+            });
+          };
+
           yubikey = mkOption {
             default = null;
             description = ''
@@ -554,6 +685,14 @@ in
       }));
     };
 
+    boot.initrd.luks.gpgSupport = mkOption {
+      default = false;
+      type = types.bool;
+      description = ''
+        Enables support for authenticating with a GPG encrypted password.
+      '';
+    };
+
     boot.initrd.luks.yubikeySupport = mkOption {
       default = false;
       type = types.bool;
@@ -567,6 +706,12 @@ in
 
   config = mkIf (luks.devices != {} || luks.forceLuksSupportInInitrd) {
 
+    assertions =
+      [ { assertion = !(luks.gpgSupport && luks.yubikeySupport);
+          message = "Yubikey and GPG Card may not be used at the same time.";
+        }
+      ];
+
     # actually, sbp2 driver is the one enabling the DMA attack, but this needs to be tested
     boot.blacklistedKernelModules = optionals luks.mitigateDMAAttacks
       ["firewire_ohci" "firewire_core" "firewire_sbp2"];
@@ -603,6 +748,23 @@ in
         EOF
         chmod +x $out/bin/openssl-wrap
       ''}
+
+      ${optionalString luks.gpgSupport ''
+        copy_bin_and_libs ${pkgs.gnupg}/bin/gpg
+        copy_bin_and_libs ${pkgs.gnupg}/bin/gpg-agent
+        copy_bin_and_libs ${pkgs.gnupg}/libexec/scdaemon
+
+        ${concatMapStringsSep "\n" (x:
+          if x.gpgCard != null then
+            ''
+              mkdir -p $out/secrets/gpg-keys/${x.device}
+              cp -a ${x.gpgCard.encryptedPass} $out/secrets/gpg-keys/${x.device}/cryptkey.gpg
+              cp -a ${x.gpgCard.publicKey} $out/secrets/gpg-keys/${x.device}/pubkey.asc
+            ''
+          else ""
+          ) (attrValues luks.devices)
+        }
+      ''}
     '';
 
     boot.initrd.extraUtilsCommandsTest = ''
@@ -612,6 +774,11 @@ in
         $out/bin/ykinfo -V
         $out/bin/openssl-wrap version
       ''}
+      ${optionalString luks.gpgSupport ''
+        $out/bin/gpg --version
+        $out/bin/gpg-agent --version
+        $out/bin/scdaemon --version
+      ''}
     '';
 
     boot.initrd.preFailCommands = postCommands;
diff --git a/nixpkgs/nixos/modules/system/boot/resolved.nix b/nixpkgs/nixos/modules/system/boot/resolved.nix
index fc68904ae080..5c66cf4a6e6e 100644
--- a/nixpkgs/nixos/modules/system/boot/resolved.nix
+++ b/nixpkgs/nixos/modules/system/boot/resolved.nix
@@ -35,7 +35,7 @@ in
         when resolving single-label host names (domain names which
         contain no dot), in order to qualify them into fully-qualified
         domain names (FQDNs).
-        </para><para>
+
         For compatibility reasons, if this setting is not specified,
         the search domains listed in
         <filename>/etc/resolv.conf</filename> are used instead, if
@@ -50,8 +50,9 @@ in
       description = ''
         Controls Link-Local Multicast Name Resolution support
         (RFC 4795) on the local host.
-        </para><para>
+
         If set to
+
         <variablelist>
         <varlistentry>
           <term><literal>"true"</literal></term>
diff --git a/nixpkgs/nixos/modules/virtualisation/docker-containers.nix b/nixpkgs/nixos/modules/virtualisation/docker-containers.nix
index c4e47bfa477c..c1f0ba303e32 100644
--- a/nixpkgs/nixos/modules/virtualisation/docker-containers.nix
+++ b/nixpkgs/nixos/modules/virtualisation/docker-containers.nix
@@ -65,10 +65,9 @@ let
           default = [];
           description = ''
             Network ports to publish from the container to the outer host.
-            </para>
-            <para>
+
             Valid formats:
-            </para>
+
             <itemizedlist>
               <listitem>
                 <para>
@@ -91,21 +90,19 @@ let
                 </para>
               </listitem>
             </itemizedlist>
-            <para>
+
             Both <literal>hostPort</literal> and
             <literal>containerPort</literal> can be specified as a range of
             ports.  When specifying ranges for both, the number of container
             ports in the range must match the number of host ports in the
             range.  Example: <literal>1234-1236:1234-1236/tcp</literal>
-            </para>
-            <para>
+
             When specifying a range for <literal>hostPort</literal> only, the
             <literal>containerPort</literal> must <emphasis>not</emphasis> be a
             range.  In this case, the container port is published somewhere
             within the specified <literal>hostPort</literal> range.  Example:
             <literal>1234-1236:1234/tcp</literal>
-            </para>
-            <para>
+
             Refer to the
             <link xlink:href="https://docs.docker.com/engine/reference/run/#expose-incoming-ports">
             Docker engine documentation</link> for full details.
diff --git a/nixpkgs/nixos/modules/virtualisation/virtualbox-host.nix b/nixpkgs/nixos/modules/virtualisation/virtualbox-host.nix
index 6f7370181740..41bcb909fb5c 100644
--- a/nixpkgs/nixos/modules/virtualisation/virtualbox-host.nix
+++ b/nixpkgs/nixos/modules/virtualisation/virtualbox-host.nix
@@ -104,7 +104,7 @@ in
       "VBoxNetNAT"
       "VBoxSDL"
       "VBoxVolInfo"
-      "VirtualBox"
+      "VirtualBoxVM"
     ]));
 
     users.groups.vboxusers.gid = config.ids.gids.vboxusers;
diff --git a/nixpkgs/nixos/tests/all-tests.nix b/nixpkgs/nixos/tests/all-tests.nix
index 95654b679609..d495b2fa6333 100644
--- a/nixpkgs/nixos/tests/all-tests.nix
+++ b/nixpkgs/nixos/tests/all-tests.nix
@@ -189,6 +189,7 @@ in
   pam-oath-login = handleTest ./pam-oath-login.nix {};
   pam-u2f = handleTest ./pam-u2f.nix {};
   pantheon = handleTest ./pantheon.nix {};
+  paperless = handleTest ./paperless.nix {};
   peerflix = handleTest ./peerflix.nix {};
   pgjwt = handleTest ./pgjwt.nix {};
   pgmanage = handleTest ./pgmanage.nix {};
diff --git a/nixpkgs/nixos/tests/docker-tools.nix b/nixpkgs/nixos/tests/docker-tools.nix
index 502b537ed68b..f91121077ea5 100644
--- a/nixpkgs/nixos/tests/docker-tools.nix
+++ b/nixpkgs/nixos/tests/docker-tools.nix
@@ -67,5 +67,12 @@ import ./make-test.nix ({ pkgs, ... }: {
       # Ensure building an image on top of a layered Docker images work
       $docker->succeed("docker load --input='${pkgs.dockerTools.examples.layered-on-top}'");
       $docker->succeed("docker run --rm ${pkgs.dockerTools.examples.layered-on-top.imageName}");
+
+      # Ensure order of layers is correct
+      $docker->succeed("docker load --input='${pkgs.dockerTools.examples.layersOrder}'");
+      $docker->succeed("docker run --rm  ${pkgs.dockerTools.examples.layersOrder.imageName} cat /tmp/layer1 | grep -q layer1");
+      # This is to be sure the order of layers of the parent image is preserved
+      $docker->succeed("docker run --rm  ${pkgs.dockerTools.examples.layersOrder.imageName} cat /tmp/layer2 | grep -q layer2");
+      $docker->succeed("docker run --rm  ${pkgs.dockerTools.examples.layersOrder.imageName} cat /tmp/layer3 | grep -q layer3");
     '';
 })
diff --git a/nixpkgs/nixos/tests/elk.nix b/nixpkgs/nixos/tests/elk.nix
index 3b3fbd73dd5f..95371ef44436 100644
--- a/nixpkgs/nixos/tests/elk.nix
+++ b/nixpkgs/nixos/tests/elk.nix
@@ -12,6 +12,11 @@ with pkgs.lib;
 let
   esUrl = "http://localhost:9200";
 
+  totalHits = message :
+    "curl --silent --show-error '${esUrl}/_search' -H 'Content-Type: application/json' " +
+    ''-d '{\"query\" : { \"match\" : { \"message\" : \"${message}\"}}}' '' +
+    "| jq .hits.total";
+
   mkElkTest = name : elk :
    let elasticsearchGe7 = builtins.compareVersions elk.elasticsearch.version "7" >= 0;
    in makeTest {
@@ -21,7 +26,7 @@ let
     };
     nodes = {
       one =
-        { pkgs, ... }: {
+        { pkgs, lib, ... }: {
             # Not giving the machine at least 2060MB results in elasticsearch failing with the following error:
             #
             #   OpenJDK 64-Bit Server VM warning:
@@ -40,6 +45,26 @@ let
             environment.systemPackages = [ pkgs.jq ];
 
             services = {
+
+              journalbeat = let lt6 = builtins.compareVersions
+                                        elk.journalbeat.version "6" < 0; in {
+                enable = true;
+                package = elk.journalbeat;
+                extraConfig = mkOptionDefault (''
+                  logging:
+                    to_syslog: true
+                    level: warning
+                    metrics.enabled: false
+                  output.elasticsearch:
+                    hosts: [ "127.0.0.1:9200" ]
+                    ${optionalString lt6 "template.enabled: false"}
+                '' + optionalString (!lt6) ''
+                  journalbeat.inputs:
+                  - paths: []
+                    seek: cursor
+                '');
+              };
+
               logstash = {
                 enable = true;
                 package = elk.logstash;
@@ -107,14 +132,19 @@ let
     testScript = ''
       startAll;
 
+      # Wait until elasticsearch is listening for connections.
       $one->waitForUnit("elasticsearch.service");
+      $one->waitForOpenPort(9200);
 
       # Continue as long as the status is not "red". The status is probably
       # "yellow" instead of "green" because we are using a single elasticsearch
       # node which elasticsearch considers risky.
       #
-      # TODO: extend this test with multiple elasticsearch nodes and see if the status turns "green".
-      $one->waitUntilSucceeds("curl --silent --show-error '${esUrl}/_cluster/health' | jq .status | grep -v red");
+      # TODO: extend this test with multiple elasticsearch nodes
+      #       and see if the status turns "green".
+      $one->waitUntilSucceeds(
+        "curl --silent --show-error '${esUrl}/_cluster/health' " .
+        "| jq .status | grep -v red");
 
       # Perform some simple logstash tests.
       $one->waitForUnit("logstash.service");
@@ -123,16 +153,28 @@ let
 
       # See if kibana is healthy.
       $one->waitForUnit("kibana.service");
-      $one->waitUntilSucceeds("curl --silent --show-error 'http://localhost:5601/api/status' | jq .status.overall.state | grep green");
+      $one->waitUntilSucceeds(
+        "curl --silent --show-error 'http://localhost:5601/api/status' " .
+        "| jq .status.overall.state | grep green");
 
       # See if logstash messages arive in elasticsearch.
-      $one->waitUntilSucceeds("curl --silent --show-error '${esUrl}/_search' -H 'Content-Type: application/json' -d '{\"query\" : { \"match\" : { \"message\" : \"flowers\"}}}' | jq .hits.total | grep -v 0");
-      $one->waitUntilSucceeds("curl --silent --show-error '${esUrl}/_search' -H 'Content-Type: application/json' -d '{\"query\" : { \"match\" : { \"message\" : \"dragons\"}}}' | jq .hits.total | grep 0");
+      $one->waitUntilSucceeds("${totalHits "flowers"} | grep -v 0");
+      $one->waitUntilSucceeds("${totalHits "dragons"} | grep 0");
+
+      # Test if a message logged to the journal
+      # is ingested by elasticsearch via journalbeat.
+      $one->waitForUnit("journalbeat.service");
+      $one->execute("echo 'Supercalifragilisticexpialidocious' | systemd-cat");
+      $one->waitUntilSucceeds(
+        "${totalHits "Supercalifragilisticexpialidocious"} | grep -v 0");
+
     '' + optionalString (!elasticsearchGe7) ''
       # Test elasticsearch-curator.
       $one->systemctl("stop logstash");
       $one->systemctl("start elasticsearch-curator");
-      $one->waitUntilSucceeds("! curl --silent --show-error '${esUrl}/_cat/indices' | grep logstash | grep -q ^$1");
+      $one->waitUntilSucceeds(
+        "! curl --silent --show-error '${esUrl}/_cat/indices' " .
+        "| grep logstash | grep -q ^$1");
     '';
   };
 in mapAttrs mkElkTest {
@@ -140,6 +182,7 @@ in mapAttrs mkElkTest {
     elasticsearch = pkgs.elasticsearch5;
     logstash      = pkgs.logstash5;
     kibana        = pkgs.kibana5;
+    journalbeat   = pkgs.journalbeat5;
   };
   "ELK-6" =
     if enableUnfree
@@ -147,11 +190,13 @@ in mapAttrs mkElkTest {
       elasticsearch = pkgs.elasticsearch6;
       logstash      = pkgs.logstash6;
       kibana        = pkgs.kibana6;
+      journalbeat   = pkgs.journalbeat6;
     }
     else {
       elasticsearch = pkgs.elasticsearch6-oss;
       logstash      = pkgs.logstash6-oss;
       kibana        = pkgs.kibana6-oss;
+      journalbeat   = pkgs.journalbeat6;
     };
   "ELK-7" =
     if enableUnfree
@@ -159,10 +204,12 @@ in mapAttrs mkElkTest {
       elasticsearch = pkgs.elasticsearch7;
       logstash      = pkgs.logstash7;
       kibana        = pkgs.kibana7;
+      journalbeat   = pkgs.journalbeat7;
     }
     else {
       elasticsearch = pkgs.elasticsearch7-oss;
       logstash      = pkgs.logstash7-oss;
       kibana        = pkgs.kibana7-oss;
+      journalbeat   = pkgs.journalbeat7;
     };
 }
diff --git a/nixpkgs/nixos/tests/gitea.nix b/nixpkgs/nixos/tests/gitea.nix
index d43efc3687a7..cccf8c7cd44f 100644
--- a/nixpkgs/nixos/tests/gitea.nix
+++ b/nixpkgs/nixos/tests/gitea.nix
@@ -9,7 +9,7 @@ with pkgs.lib;
 {
   mysql = makeTest {
     name = "gitea-mysql";
-    meta.maintainers = [ maintainers.aanderse ];
+    meta.maintainers = with maintainers; [ aanderse kolaente ];
 
     machine =
       { config, pkgs, ... }:
diff --git a/nixpkgs/nixos/tests/hardened.nix b/nixpkgs/nixos/tests/hardened.nix
index 07bd10963bab..1ff329bd98de 100644
--- a/nixpkgs/nixos/tests/hardened.nix
+++ b/nixpkgs/nixos/tests/hardened.nix
@@ -27,9 +27,33 @@ import ./make-test.nix ({ pkgs, ...} : {
     };
 
   testScript =
+    let
+      hardened-malloc-tests = pkgs.stdenv.mkDerivation rec {
+        name = "hardened-malloc-tests-${pkgs.graphene-hardened-malloc.version}";
+        src = pkgs.graphene-hardened-malloc.src;
+        buildPhase = ''
+          cd test/simple-memory-corruption
+          make -j4
+        '';
+
+        installPhase = ''
+          find . -type f -executable -exec install -Dt $out/bin '{}' +
+        '';
+      };
+    in
     ''
       $machine->waitForUnit("multi-user.target");
 
+      subtest "apparmor-loaded", sub {
+          $machine->succeed("systemctl status apparmor.service");
+      };
+
+      # AppArmor securityfs
+      subtest "apparmor-securityfs", sub {
+          $machine->succeed("mountpoint -q /sys/kernel/security");
+          $machine->succeed("cat /sys/kernel/security/apparmor/profiles");
+      };
+
       # Test loading out-of-tree modules
       subtest "extra-module-packages", sub {
           $machine->succeed("grep -Fq wireguard /proc/modules");
@@ -83,5 +107,18 @@ import ./make-test.nix ({ pkgs, ...} : {
         $machine->fail("systemctl hibernate");
         $machine->fail("systemctl kexec");
       };
+
+      # Test hardened memory allocator
+      sub runMallocTestProg {
+          my ($progName, $errorText) = @_;
+          my $text = "fatal allocator error: " . $errorText;
+          $machine->fail("${hardened-malloc-tests}/bin/" . $progName) =~ $text;
+      };
+
+      subtest "hardenedmalloc", sub {
+        runMallocTestProg("double_free_large", "invalid free");
+        runMallocTestProg("unaligned_free_small", "invalid unaligned free");
+        runMallocTestProg("write_after_free_small", "detected write after free");
+      };
     '';
 })
diff --git a/nixpkgs/nixos/tests/paperless.nix b/nixpkgs/nixos/tests/paperless.nix
new file mode 100644
index 000000000000..860ad0a6218f
--- /dev/null
+++ b/nixpkgs/nixos/tests/paperless.nix
@@ -0,0 +1,29 @@
+import ./make-test.nix ({ lib, ... } : {
+  name = "paperless";
+  meta = with lib.maintainers; {
+    maintainers = [ earvstedt ];
+  };
+
+  machine = { pkgs, ... }: {
+    environment.systemPackages = with pkgs; [ imagemagick jq ];
+    services.paperless = {
+      enable = true;
+      ocrLanguages = [ "eng" ];
+    };
+  };
+
+  testScript = ''
+    $machine->waitForUnit("paperless-consumer.service");
+    # Create test doc
+    $machine->succeed('convert -size 400x40 xc:white -font "DejaVu-Sans" -pointsize 20 -fill black \
+      -annotate +5+20 "hello world 16-10-2005" /var/lib/paperless/consume/doc.png');
+
+    $machine->waitForUnit("paperless-server.service");
+    # Wait until server accepts connections
+    $machine->waitUntilSucceeds("curl -s localhost:28981");
+    # Wait until document is consumed
+    $machine->waitUntilSucceeds('(($(curl -s localhost:28981/api/documents/ | jq .count) == 1))');
+    $machine->succeed("curl -s localhost:28981/api/documents/ | jq '.results | .[0] | .created'")
+      =~ /2005-10-16/ or die;
+  '';
+})
diff --git a/nixpkgs/nixos/tests/virtualbox.nix b/nixpkgs/nixos/tests/virtualbox.nix
index 84d5f3e1530e..844ce47d743f 100644
--- a/nixpkgs/nixos/tests/virtualbox.nix
+++ b/nixpkgs/nixos/tests/virtualbox.nix
@@ -2,9 +2,26 @@
   config ? {},
   pkgs ? import ../.. { inherit system config; },
   debug ? false,
-  enableUnfree ? false
+  enableUnfree ? false,
+  # Nested KVM virtualization (https://www.linux-kvm.org/page/Nested_Guests)
+  # requires a modprobe flag on the build machine: (kvm-amd for AMD CPUs)
+  #   boot.extraModprobeConfig = "options kvm-intel nested=Y";
+  # Without this VirtualBox will use SW virtualization and will only be able
+  # to run 32-bit guests.
+  useKvmNestedVirt ? false,
+  # Whether to run 64-bit guests instead of 32-bit. Requires nested KVM.
+  use64bitGuest ? false,
+  # Whether to enable the virtual UART in VirtualBox guests, allowing to see
+  # the guest console. There is currently a bug in VirtualBox where this will
+  # cause a crash if running with SW virtualization
+  # (https://www.virtualbox.org/ticket/18632). If you need to debug the tests
+  # then enable this and nested KVM to work around the crash (see above).
+  enableVBoxUART ? false
 }:
 
+assert use64bitGuest -> useKvmNestedVirt;
+assert enableVBoxUART -> useKvmNestedVirt; # VirtualBox bug, see above
+
 with import ../lib/testing.nix { inherit system pkgs; };
 with pkgs.lib;
 
@@ -94,7 +111,7 @@ let
 
   testVM = vmName: vmScript: let
     cfg = (import ../lib/eval-config.nix {
-      system = "i686-linux";
+      system = if use64bitGuest then "x86_64-linux" else "i686-linux";
       modules = [
         ../modules/profiles/minimal.nix
         (testVMConfig vmName vmScript)
@@ -141,13 +158,15 @@ let
     sharePath = "/home/alice/vboxshare-${name}";
 
     createFlags = mkFlags [
-      "--ostype Linux26"
+      "--ostype ${if use64bitGuest then "Linux26_64" else "Linux26"}"
       "--register"
     ];
 
-    vmFlags = mkFlags ([
-      "--uart1 0x3F8 4"
-      "--uartmode1 client /run/virtualbox-log-${name}.sock"
+    vmFlags = mkFlags (
+      (optionals enableVBoxUART [
+        "--uart1 0x3F8 4"
+        "--uartmode1 client /run/virtualbox-log-${name}.sock"
+      ]) ++ [
       "--memory 768"
       "--audio none"
     ] ++ (attrs.vmFlags or []));
@@ -180,7 +199,7 @@ let
     ];
   in {
     machine = {
-      systemd.sockets."vboxtestlog-${name}" = {
+      systemd.sockets."vboxtestlog-${name}" = mkIf enableVBoxUART {
         description = "VirtualBox Test Machine Log Socket For ${name}";
         wantedBy = [ "sockets.target" ];
         before = [ "multi-user.target" ];
@@ -188,7 +207,7 @@ let
         socketConfig.Accept = true;
       };
 
-      systemd.services."vboxtestlog-${name}@" = {
+      systemd.services."vboxtestlog-${name}@" = mkIf enableVBoxUART {
         description = "VirtualBox Test Machine Log For ${name}";
         serviceConfig.StandardInput = "socket";
         serviceConfig.StandardOutput = "syslog";
@@ -346,6 +365,8 @@ let
         vmConfigs = mapAttrsToList mkVMConf vms;
       in [ ./common/user-account.nix ./common/x11.nix ] ++ vmConfigs;
       virtualisation.memorySize = 2048;
+      virtualisation.qemu.options =
+        if useKvmNestedVirt then ["-cpu" "kvm64,vmx=on"] else [];
       virtualisation.virtualbox.host.enable = true;
       services.xserver.displayManager.auto.user = "alice";
       users.users.alice.extraGroups = let
@@ -412,9 +433,14 @@ in mapAttrs (mkVBoxTest false vboxVMs) {
     );
     $machine->sleep(5);
     $machine->screenshot("gui_manager_started");
+    # Home to select Tools, down to move to the VM, enter to start it.
+    $machine->sendKeys("home");
+    $machine->sendKeys("down");
     $machine->sendKeys("ret");
     $machine->screenshot("gui_manager_sent_startup");
     waitForStartup_simple (sub {
+      $machine->sendKeys("home");
+      $machine->sendKeys("down");
       $machine->sendKeys("ret");
     });
     $machine->screenshot("gui_started");
diff --git a/nixpkgs/nixos/tests/xss-lock.nix b/nixpkgs/nixos/tests/xss-lock.nix
index b46bb1a8f6e9..0d757e8cef3f 100644
--- a/nixpkgs/nixos/tests/xss-lock.nix
+++ b/nixpkgs/nixos/tests/xss-lock.nix
@@ -6,19 +6,35 @@ with lib;
   name = "xss-lock";
   meta.maintainers = with pkgs.stdenv.lib.maintainers; [ ma27 ];
 
-  machine = {
-    imports = [ ./common/x11.nix ./common/user-account.nix ];
-    programs.xss-lock.enable = true;
-    services.xserver.displayManager.auto.user = "alice";
+  nodes = {
+    simple = {
+      imports = [ ./common/x11.nix ./common/user-account.nix ];
+      programs.xss-lock.enable = true;
+      services.xserver.displayManager.auto.user = "alice";
+    };
+
+    custom_lockcmd = { pkgs, ... }: {
+      imports = [ ./common/x11.nix ./common/user-account.nix ];
+      services.xserver.displayManager.auto.user = "alice";
+
+      programs.xss-lock = {
+        enable = true;
+        extraOptions = [ "-n" "${pkgs.libnotify}/bin/notify-send 'About to sleep!'"];
+        lockerCommand = "${pkgs.xlockmore}/bin/xlock -mode ant";
+      };
+    };
   };
 
   testScript = ''
-    $machine->start;
-    $machine->waitForX;
-    $machine->waitForUnit("xss-lock.service", "alice");
+    startAll;
 
-    $machine->fail("pgrep xlock");
-    $machine->succeed("su -l alice -c 'xset dpms force standby'");
-    $machine->waitUntilSucceeds("pgrep i3lock");
+    ${concatStringsSep "\n" (mapAttrsToList (name: lockCmd: ''
+      ${"$"+name}->start;
+      ${"$"+name}->waitForX;
+      ${"$"+name}->waitForUnit("xss-lock.service", "alice");
+      ${"$"+name}->fail("pgrep ${lockCmd}");
+      ${"$"+name}->succeed("su -l alice -c 'xset dpms force standby'");
+      ${"$"+name}->waitUntilSucceeds("pgrep ${lockCmd}");
+    '') { simple = "i3lock"; custom_lockcmd = "xlock"; })}
   '';
 })