summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/installation/upgrading.xml5
-rw-r--r--nixos/lib/make-disk-image.nix21
-rw-r--r--nixos/lib/test-driver/Machine.pm25
-rw-r--r--nixos/modules/installer/netboot/netboot.nix28
-rw-r--r--nixos/modules/misc/ids.nix2
-rw-r--r--nixos/modules/module-list.nix2
-rw-r--r--nixos/modules/security/acme.nix1
-rw-r--r--nixos/modules/security/acme.xml2
-rw-r--r--nixos/modules/security/grsecurity.nix50
-rw-r--r--nixos/modules/security/grsecurity.xml19
-rw-r--r--nixos/modules/security/hidepid.nix2
-rw-r--r--nixos/modules/services/misc/gitlab.nix2
-rw-r--r--nixos/modules/services/network-filesystems/ipfs.nix14
-rw-r--r--nixos/modules/services/networking/privoxy.nix23
-rw-r--r--nixos/modules/services/networking/wireguard.nix3
-rw-r--r--nixos/modules/services/system/cgmanager.nix27
-rw-r--r--nixos/modules/services/x11/display-managers/default.nix1
-rw-r--r--nixos/modules/services/x11/display-managers/gdm.nix7
-rw-r--r--nixos/modules/services/x11/display-managers/kdm.nix2
-rw-r--r--nixos/modules/services/x11/display-managers/lightdm.nix2
-rw-r--r--nixos/modules/services/x11/display-managers/sddm.nix2
-rw-r--r--nixos/modules/services/x11/display-managers/slim.nix2
-rw-r--r--nixos/modules/virtualisation/containers.nix2
-rw-r--r--nixos/modules/virtualisation/lxcfs.nix49
-rw-r--r--nixos/tests/blivet.nix2
-rw-r--r--nixos/tests/ecryptfs.nix21
-rw-r--r--nixos/tests/ipfs.nix37
-rw-r--r--nixos/tests/login.nix5
28 files changed, 300 insertions, 58 deletions
diff --git a/nixos/doc/manual/installation/upgrading.xml b/nixos/doc/manual/installation/upgrading.xml
index 65d395b0c88..c974523f886 100644
--- a/nixos/doc/manual/installation/upgrading.xml
+++ b/nixos/doc/manual/installation/upgrading.xml
@@ -101,6 +101,11 @@ channel by running
 which is equivalent to the more verbose <literal>nix-channel --update
 nixos; nixos-rebuild switch</literal>.</para>
 
+<note><para>Channels are set per user. This means that running <literal>
+nix-channel --add</literal> as a non root user (or without sudo) will not
+affect configuration in <literal>/etc/nixos/configuration.nix</literal>
+</para></note>
+
 <warning><para>It is generally safe to switch back and forth between
 channels.  The only exception is that a newer NixOS may also have a
 newer Nix version, which may involve an upgrade of Nix’s database
diff --git a/nixos/lib/make-disk-image.nix b/nixos/lib/make-disk-image.nix
index 58d0cb38d75..e279803f2ea 100644
--- a/nixos/lib/make-disk-image.nix
+++ b/nixos/lib/make-disk-image.nix
@@ -27,6 +27,10 @@
 
 , name ? "nixos-disk-image"
 
+  # This prevents errors while checking nix-store validity, see
+  # https://github.com/NixOS/nix/issues/1134
+, fixValidity ? true
+
 , format ? "raw"
 }:
 
@@ -61,9 +65,6 @@ pkgs.vmTools.runInLinuxVM (
 
       # Create an empty filesystem and mount it.
       mkfs.${fsType} -L nixos $rootDisk
-      ${optionalString (fsType == "ext4") ''
-        tune2fs -c 0 -i 0 $rootDisk
-      ''}
       mkdir /mnt
       mount $rootDisk /mnt
 
@@ -71,9 +72,11 @@ pkgs.vmTools.runInLinuxVM (
       printRegistration=1 perl ${pkgs.pathsFromGraph} /tmp/xchg/closure | \
           ${config.nix.package.out}/bin/nix-store --load-db --option build-users-group ""
 
-      # Add missing size/hash fields to the database. FIXME:
-      # exportReferencesGraph should provide these directly.
-      ${config.nix.package.out}/bin/nix-store --verify --check-contents --option build-users-group ""
+      ${if fixValidity then ''
+        # Add missing size/hash fields to the database. FIXME:
+        # exportReferencesGraph should provide these directly.
+        ${config.nix.package.out}/bin/nix-store --verify --check-contents --option build-users-group ""
+      '' else ""}
 
       # In case the bootloader tries to write to /dev/sda…
       ln -s vda /dev/xvda
@@ -97,7 +100,9 @@ pkgs.vmTools.runInLinuxVM (
 
       umount /mnt
 
-      # Do a fsck to make sure resize2fs works.
-      fsck.${fsType} -f -y $rootDisk
+      # Make sure resize2fs works
+      ${optionalString (fsType == "ext4") ''
+        tune2fs -c 0 -i 0 $rootDisk
+      ''}
     ''
 )
diff --git a/nixos/lib/test-driver/Machine.pm b/nixos/lib/test-driver/Machine.pm
index 1a243918c22..274b16164db 100644
--- a/nixos/lib/test-driver/Machine.pm
+++ b/nixos/lib/test-driver/Machine.pm
@@ -504,6 +504,31 @@ sub screenshot {
     }, { image => $name } );
 }
 
+# Get the text of TTY<n>
+sub getTTYText {
+    my ($self, $tty) = @_;
+
+    my ($status, $out) = $self->execute("fold -w 80 /dev/vcs${tty}");
+    return $out;
+}
+
+# Wait until TTY<n>'s text matches a particular regular expression
+sub waitUntilTTYMatches {
+    my ($self, $tty, $regexp) = @_;
+
+    $self->nest("waiting for $regexp to appear on tty $tty", sub {
+        retry sub {
+            return 1 if $self->getTTYText($tty) =~ /$regexp/;
+        }
+    });
+}
+
+# Debugging: Dump the contents of the TTY<n>
+sub dumpTTYContents {
+    my ($self, $tty) = @_;
+
+    $self->execute("fold -w 80 /dev/vcs${tty} | systemd-cat");
+}
 
 # Take a screenshot and return the result as text using optical character
 # recognition.
diff --git a/nixos/modules/installer/netboot/netboot.nix b/nixos/modules/installer/netboot/netboot.nix
index 366591a8114..5908ff6cb94 100644
--- a/nixos/modules/installer/netboot/netboot.nix
+++ b/nixos/modules/installer/netboot/netboot.nix
@@ -26,11 +26,6 @@ with lib;
     # here and it causes a cyclic dependency.
     boot.loader.grub.enable = false;
 
-    boot.initrd.postMountCommands = ''
-      mkdir -p /mnt-root/nix/store
-      mount -t squashfs /nix-store.squashfs /mnt-root/nix/store
-    '';
-
     # !!! Hack - attributes expected by other modules.
     system.boot.loader.kernelFile = "bzImage";
     environment.systemPackages = [ pkgs.grub2 pkgs.grub2_efi pkgs.syslinux ];
@@ -42,13 +37,34 @@ with lib;
         options = [ "mode=0755" ];
       };
 
+    # In stage 1, mount a tmpfs on top of /nix/store (the squashfs
+    # image) to make this a live CD.
+    fileSystems."/nix/.ro-store" =
+      { fsType = "squashfs";
+        device = "../nix-store.squashfs";
+        options = [ "loop" ];
+        neededForBoot = true;
+      };
+
+    fileSystems."/nix/.rw-store" =
+      { fsType = "tmpfs";
+        options = [ "mode=0755" ];
+        neededForBoot = true;
+      };
+
+    fileSystems."/nix/store" =
+      { fsType = "unionfs-fuse";
+        device = "unionfs";
+        options = [ "allow_other" "cow" "nonempty" "chroot=/mnt-root" "max_files=32768" "hide_meta_files" "dirs=/nix/.rw-store=rw:/nix/.ro-store=ro" ];
+      };
+
     boot.initrd.availableKernelModules = [ "squashfs" ];
 
     boot.initrd.kernelModules = [ "loop" ];
 
     # Closures to be copied to the Nix store, namely the init
     # script and the top-level system configuration directory.
-   netboot.storeContents =
+    netboot.storeContents =
       [ config.system.build.toplevel ];
 
     # Create the squashfs image that contains the Nix store.
diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix
index 41ee63a9603..bc69102ba39 100644
--- a/nixos/modules/misc/ids.nix
+++ b/nixos/modules/misc/ids.nix
@@ -58,7 +58,6 @@
       #utmp = 29; # unused
       ddclient = 30;
       davfs2 = 31;
-      privoxy = 32;
       #disnix = 33; # unused
       osgi = 34;
       tor = 35;
@@ -322,7 +321,6 @@
       utmp = 29;
       #ddclient = 30; # unused
       davfs2 = 31;
-      privoxy = 32;
       disnix = 33;
       osgi = 34;
       tor = 35;
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 5ae69ffd223..155d7a5ef92 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -483,6 +483,7 @@
   ./services/security/torify.nix
   ./services/security/tor.nix
   ./services/security/torsocks.nix
+  ./services/system/cgmanager.nix
   ./services/system/cloud-init.nix
   ./services/system/dbus.nix
   ./services/system/kerberos.nix
@@ -617,6 +618,7 @@
   ./virtualisation/docker.nix
   ./virtualisation/libvirtd.nix
   ./virtualisation/lxc.nix
+  ./virtualisation/lxcfs.nix
   ./virtualisation/lxd.nix
   ./virtualisation/amazon-options.nix
   ./virtualisation/openvswitch.nix
diff --git a/nixos/modules/security/acme.nix b/nixos/modules/security/acme.nix
index 12736e57b4a..726e5471141 100644
--- a/nixos/modules/security/acme.nix
+++ b/nixos/modules/security/acme.nix
@@ -178,6 +178,7 @@ in
                   path = [ pkgs.simp_le ];
                   preStart = ''
                     mkdir -p '${cfg.directory}'
+                    chown '${data.user}:${data.group}' '${cfg.directory}'
                     if [ ! -d '${cpath}' ]; then
                       mkdir '${cpath}'
                     fi
diff --git a/nixos/modules/security/acme.xml b/nixos/modules/security/acme.xml
index 226cf0382da..6fddb27e6a3 100644
--- a/nixos/modules/security/acme.xml
+++ b/nixos/modules/security/acme.xml
@@ -75,7 +75,7 @@ options for the <literal>security.acme</literal> module.</para>
 
 <programlisting>
 security.acme.certs."foo.example.com" = {
-  webroot = "/var/www/challenges";
+  webroot = config.security.acme.directory + "/acme-challenge";
   email = "foo@example.com";
   user = "nginx";
   group = "nginx";
diff --git a/nixos/modules/security/grsecurity.nix b/nixos/modules/security/grsecurity.nix
index 92afb74956e..3726b6c7818 100644
--- a/nixos/modules/security/grsecurity.nix
+++ b/nixos/modules/security/grsecurity.nix
@@ -59,7 +59,8 @@ in
 
     boot.kernelPackages = mkForce pkgs.linuxPackages_grsec_nixos;
 
-    boot.kernelParams = optional cfg.disableEfiRuntimeServices "noefi";
+    boot.kernelParams = [ "grsec_sysfs_restrict=0" ]
+      ++ optional cfg.disableEfiRuntimeServices "noefi";
 
     nixpkgs.config.grsecurity = true;
 
@@ -109,19 +110,62 @@ in
     boot.kernel.sysctl = {
       # Read-only under grsecurity
       "kernel.kptr_restrict" = mkForce null;
+
+      # All grsec tunables default to off, those not enabled below are
+      # *disabled*.  We use mkDefault to allow expert users to override
+      # our choices, but use mkForce where tunables would outright
+      # conflict with other settings.
+
+      # Enable all chroot restrictions by default (overwritten as
+      # necessary below)
+      "kernel.grsecurity.chroot_caps" = mkDefault 1;
+      "kernel.grsecurity.chroot_deny_bad_rename" = mkDefault 1;
+      "kernel.grsecurity.chroot_deny_chmod" = mkDefault 1;
+      "kernel.grsecurity.chroot_deny_chroot" = mkDefault 1;
+      "kernel.grsecurity.chroot_deny_fchdir" = mkDefault 1;
+      "kernel.grsecurity.chroot_deny_mknod" = mkDefault 1;
+      "kernel.grsecurity.chroot_deny_mount" = mkDefault 1;
+      "kernel.grsecurity.chroot_deny_pivot" = mkDefault 1;
+      "kernel.grsecurity.chroot_deny_shmat" = mkDefault 1;
+      "kernel.grsecurity.chroot_deny_sysctl" = mkDefault 1;
+      "kernel.grsecurity.chroot_deny_unix" = mkDefault 1;
+      "kernel.grsecurity.chroot_enforce_chdir" = mkDefault 1;
+      "kernel.grsecurity.chroot_findtask" = mkDefault 1;
+      "kernel.grsecurity.chroot_restrict_nice" = mkDefault 1;
+
+      # Enable various grsec protections
+      "kernel.grsecurity.consistent_setxid" = mkDefault 1;
+      "kernel.grsecurity.deter_bruteforce" = mkDefault 1;
+      "kernel.grsecurity.fifo_restrictions" = mkDefault 1;
+      "kernel.grsecurity.harden_ipc" = mkDefault 1;
+      "kernel.grsecurity.harden_ptrace" = mkDefault 1;
+      "kernel.grsecurity.harden_tty" = mkDefault 1;
+      "kernel.grsecurity.ip_blackhole" = mkDefault 1;
+      "kernel.grsecurity.linking_restrictions" = mkDefault 1;
+      "kernel.grsecurity.ptrace_readexec" = mkDefault 1;
+
+      # Enable auditing
+      "kernel.grsecurity.audit_ptrace" = mkDefault 1;
+      "kernel.grsecurity.forkfail_logging" = mkDefault 1;
+      "kernel.grsecurity.rwxmap_logging" = mkDefault 1;
+      "kernel.grsecurity.signal_logging" = mkDefault 1;
+      "kernel.grsecurity.timechange_logging" = mkDefault 1;
     } // optionalAttrs config.nix.useSandbox {
       # chroot(2) restrictions that conflict with sandboxed Nix builds
       "kernel.grsecurity.chroot_caps" = mkForce 0;
+      "kernel.grsecurity.chroot_deny_chmod" = mkForce 0;
       "kernel.grsecurity.chroot_deny_chroot" = mkForce 0;
       "kernel.grsecurity.chroot_deny_mount" = mkForce 0;
       "kernel.grsecurity.chroot_deny_pivot" = mkForce 0;
-      "kernel.grsecurity.chroot_deny_chmod" = mkForce 0;
     } // optionalAttrs containerSupportRequired {
       # chroot(2) restrictions that conflict with NixOS lightweight containers
+      "kernel.grsecurity.chroot_caps" = mkForce 0;
       "kernel.grsecurity.chroot_deny_chmod" = mkForce 0;
       "kernel.grsecurity.chroot_deny_mount" = mkForce 0;
       "kernel.grsecurity.chroot_restrict_nice" = mkForce 0;
-      "kernel.grsecurity.chroot_caps" = mkForce 0;
+      # Disable privileged IO by default, unless X is enabled
+    } // optionalAttrs (!config.services.xserver.enable) {
+      "kernel.grsecurity.disable_priv_io" = mkDefault 1;
     };
 
   };
diff --git a/nixos/modules/security/grsecurity.xml b/nixos/modules/security/grsecurity.xml
index e41748358fb..5b3e4db03a1 100644
--- a/nixos/modules/security/grsecurity.xml
+++ b/nixos/modules/security/grsecurity.xml
@@ -151,15 +151,8 @@
         a TCP simultaneous OPEN on that port before the connection is actually
         established.</para></listitem>
 
-        <listitem><para><filename class="directory">/sys</filename> hardening:
-        breaks systemd.</para></listitem>
-
         <listitem><para>Trusted path execution: a desirable feature, but
         requires some more work to operate smoothly on NixOS.</para></listitem>
-
-        <listitem><para>Module hardening: would break user initiated module
-        loading. Might enable this at some point, depending on the potential
-        breakage.</para></listitem>
       </itemizedlist>
     </para></listitem>
 
@@ -295,6 +288,10 @@
     <option>security.grsecurity.disableEfiRuntimeServices</option> to override
     this behavior.</para></listitem>
 
+    <listitem><para>User initiated autoloading of modules (e.g., when
+    using fuse or loop devices) is disallowed; either load requisite modules
+    as root or add them to<option>boot.kernelModules</option>.</para></listitem>
+
     <listitem><para>Virtualization: KVM is the preferred virtualization
     solution. Xen, Virtualbox, and VMWare are
     <emphasis>unsupported</emphasis> and most likely require a custom kernel.
@@ -350,13 +347,19 @@
 
       <listitem><para>
         <literal>pax_sanitize_slab={off|fast|full}</literal>: control kernel
-        slab object sanitization
+        slab object sanitization. Defaults to <literal>fast</literal>
       </para></listitem>
 
       <listitem><para>
         <literal>pax_size_overflow_report_only</literal>: log size overflow
         violations but leave the violating task running
       </para></listitem>
+
+      <listitem><para>
+        <literal>grsec_sysfs_restrict=[0|1]</literal>: toggle sysfs
+        restrictions. The NixOS module sets this to <literal>0</literal>
+        for systemd compatibility
+      </para></listitem>
     </itemizedlist>
   </para>
 
diff --git a/nixos/modules/security/hidepid.nix b/nixos/modules/security/hidepid.nix
index ee351eb8447..96443fda758 100644
--- a/nixos/modules/security/hidepid.nix
+++ b/nixos/modules/security/hidepid.nix
@@ -19,7 +19,9 @@ with lib;
 
   config = mkIf config.security.hideProcessInformation {
     users.groups.proc.gid = config.ids.gids.proc;
+    users.groups.proc.members = [ "polkituser" ];
 
     boot.specialFileSystems."/proc".options = [ "hidepid=2" "gid=${toString config.ids.gids.proc}" ];
+    systemd.services.systemd-logind.serviceConfig.SupplementaryGroups = [ "proc" ];
   };
 }
diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix
index cb8fa901bbd..1fc3a5cc869 100644
--- a/nixos/modules/services/misc/gitlab.nix
+++ b/nixos/modules/services/misc/gitlab.nix
@@ -428,7 +428,7 @@ in {
         TimeoutSec = "300";
         Restart = "on-failure";
         WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab";
-        ExecStart="${cfg.packages.gitlab.env}/bin/bundle exec \"sidekiq -q post_receive -q mailers -q system_hook -q project_web_hook -q gitlab_shell -q common -q default -e production -P ${cfg.statePath}/tmp/sidekiq.pid\"";
+        ExecStart="${cfg.packages.gitlab.env}/bin/bundle exec \"sidekiq -C \"${cfg.packages.gitlab}/share/gitlab/config/sidekiq_queues.yml\" -e production -P ${cfg.statePath}/tmp/sidekiq.pid\"";
       };
     };
 
diff --git a/nixos/modules/services/network-filesystems/ipfs.nix b/nixos/modules/services/network-filesystems/ipfs.nix
index c26a7073703..104b5b92620 100644
--- a/nixos/modules/services/network-filesystems/ipfs.nix
+++ b/nixos/modules/services/network-filesystems/ipfs.nix
@@ -47,6 +47,18 @@ in
         '';
       };
 
+      gatewayAddress = mkOption {
+        type = types.str;
+        default = "/ip4/127.0.0.1/tcp/8080";
+        description = "Where the IPFS Gateway can be reached";
+      };
+
+      apiAddress = mkOption {
+        type = types.str;
+        default = "/ip4/127.0.0.1/tcp/5001";
+        description = "Where IPFS exposes its API to";
+      };
+
       enableGC = mkOption {
         type = types.bool;
         default = false;
@@ -98,6 +110,8 @@ in
             cd ${cfg.dataDir}
             ${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${cfg.user} -c "${ipfs}/bin/ipfs init"
           fi
+          ${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${cfg.user} -c "${ipfs}/bin/ipfs config Addresses.API ${cfg.apiAddress}"
+          ${pkgs.su}/bin/su -s ${pkgs.bash}/bin/sh ${cfg.user} -c "${ipfs}/bin/ipfs config Addresses.Gateway ${cfg.gatewayAddress}"
         '';
 
       serviceConfig = {
diff --git a/nixos/modules/services/networking/privoxy.nix b/nixos/modules/services/networking/privoxy.nix
index 94beb78ef5a..49ca839a2c3 100644
--- a/nixos/modules/services/networking/privoxy.nix
+++ b/nixos/modules/services/networking/privoxy.nix
@@ -6,8 +6,6 @@ let
 
   inherit (pkgs) privoxy;
 
-  privoxyUser = "privoxy";
-
   cfg = config.services.privoxy;
 
   confFile = pkgs.writeText "privoxy.conf" ''
@@ -88,18 +86,25 @@ in
   ###### implementation
 
   config = mkIf cfg.enable {
-  
-    users.extraUsers = singleton
-      { name = privoxyUser;
-        uid = config.ids.uids.privoxy;
-        description = "Privoxy daemon user";
-      };
+
+    users.users.privoxy = {
+      isSystemUser = true;
+      home = "/var/empty";
+      group = "privoxy";
+    };
+
+    users.groups.privoxy = {};
 
     systemd.services.privoxy = {
       description = "Filtering web proxy";
       after = [ "network.target" "nss-lookup.target" ];
       wantedBy = [ "multi-user.target" ];
-      serviceConfig.ExecStart = "${privoxy}/sbin/privoxy --no-daemon --user ${privoxyUser} ${confFile}";
+      serviceConfig.ExecStart = "${privoxy}/bin/privoxy --no-daemon --user privoxy ${confFile}";
+
+      serviceConfig.PrivateDevices = true;
+      serviceConfig.PrivateTmp = true;
+      serviceConfig.ProtectHome = true;
+      serviceConfig.ProtectSystem = "full";
     };
 
   };
diff --git a/nixos/modules/services/networking/wireguard.nix b/nixos/modules/services/networking/wireguard.nix
index 35918e42b40..52dd5502147 100644
--- a/nixos/modules/services/networking/wireguard.nix
+++ b/nixos/modules/services/networking/wireguard.nix
@@ -151,7 +151,8 @@ let
     nameValuePair "wireguard-${name}"
       {
         description = "WireGuard Tunnel - ${name}";
-        wantedBy = [ "ip-up.target" ];
+        after = [ "network.target" ];
+        wantedBy = [ "multi-user.target" ];
         serviceConfig = {
           Type = "oneshot";
           RemainAfterExit = true;
diff --git a/nixos/modules/services/system/cgmanager.nix b/nixos/modules/services/system/cgmanager.nix
new file mode 100644
index 00000000000..59d3deced86
--- /dev/null
+++ b/nixos/modules/services/system/cgmanager.nix
@@ -0,0 +1,27 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.services.cgmanager;
+in {
+  meta.maintainers = [ maintainers.mic92 ];
+
+  ###### interface
+  options.services.cgmanager.enable = mkEnableOption "cgmanager";
+
+  ###### implementation
+  config = mkIf cfg.enable {
+    systemd.services.cgmanager = {
+      wantedBy = [ "multi-user.target" ];
+      after = [ "local-fs.target" ];
+      description = "Cgroup management daemon";
+      restartIfChanged = false;
+      serviceConfig = {
+        ExecStart = "${pkgs.cgmanager}/bin/cgmanager -m name=systemd";
+        KillMode = "process";
+        Restart = "on-failure";
+      };
+    };
+  };
+}
diff --git a/nixos/modules/services/x11/display-managers/default.nix b/nixos/modules/services/x11/display-managers/default.nix
index c8a1a2361f7..c0daf30d04e 100644
--- a/nixos/modules/services/x11/display-managers/default.nix
+++ b/nixos/modules/services/x11/display-managers/default.nix
@@ -187,7 +187,6 @@ in
         default = [];
         example = [ "-ac" "-logverbose" "-verbose" "-nolisten tcp" ];
         description = "List of arguments for the X server.";
-        apply = toString;
       };
 
       sessionCommands = mkOption {
diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix
index d3aa63fd428..6c63fede857 100644
--- a/nixos/modules/services/x11/display-managers/gdm.nix
+++ b/nixos/modules/services/x11/display-managers/gdm.nix
@@ -92,10 +92,15 @@ in
 
     users.extraGroups.gdm.gid = config.ids.gids.gdm;
 
+    # GDM needs different xserverArgs, presumable because using wayland by default.
+    services.xserver.tty = null;
+    services.xserver.display = null;
+
     services.xserver.displayManager.job =
       {
         environment = {
-          GDM_X_SERVER_EXTRA_ARGS = "${cfg.xserverArgs}";
+          GDM_X_SERVER_EXTRA_ARGS = toString
+            (filter (arg: arg != "-terminate") cfg.xserverArgs);
           GDM_SESSIONS_DIR = "${cfg.session.desktops}";
           # Find the mouse
           XCURSOR_PATH = "~/.icons:${config.system.path}/share/icons";
diff --git a/nixos/modules/services/x11/display-managers/kdm.nix b/nixos/modules/services/x11/display-managers/kdm.nix
index 8b51c621e11..04701a1640c 100644
--- a/nixos/modules/services/x11/display-managers/kdm.nix
+++ b/nixos/modules/services/x11/display-managers/kdm.nix
@@ -25,7 +25,7 @@ let
       FailsafeClient=${pkgs.xterm}/bin/xterm
 
       [X-:*-Core]
-      ServerCmd=${dmcfg.xserverBin} ${dmcfg.xserverArgs}
+      ServerCmd=${dmcfg.xserverBin} ${toString dmcfg.xserverArgs}
       # KDM calls `rm' somewhere to clean up some temporary directory.
       SystemPath=${pkgs.coreutils}/bin
       # The default timeout (15) is too short in a heavily loaded boot process.
diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix
index 1d309aa3429..4afef32aaa4 100644
--- a/nixos/modules/services/x11/display-managers/lightdm.nix
+++ b/nixos/modules/services/x11/display-managers/lightdm.nix
@@ -23,7 +23,7 @@ let
       else additionalArgs="-logfile /var/log/X.$display.log"
       fi
 
-      exec ${dmcfg.xserverBin} ${dmcfg.xserverArgs} $additionalArgs "$@"
+      exec ${dmcfg.xserverBin} ${toString dmcfg.xserverArgs} $additionalArgs "$@"
     '';
 
   usersConf = writeText "users.conf"
diff --git a/nixos/modules/services/x11/display-managers/sddm.nix b/nixos/modules/services/x11/display-managers/sddm.nix
index dda8d0f7629..6630b8257e4 100644
--- a/nixos/modules/services/x11/display-managers/sddm.nix
+++ b/nixos/modules/services/x11/display-managers/sddm.nix
@@ -14,7 +14,7 @@ let
   xserverWrapper = pkgs.writeScript "xserver-wrapper" ''
     #!/bin/sh
     ${concatMapStrings (n: "export ${n}=\"${getAttr n xEnv}\"\n") (attrNames xEnv)}
-    exec systemd-cat ${dmcfg.xserverBin} ${dmcfg.xserverArgs} "$@"
+    exec systemd-cat ${dmcfg.xserverBin} ${toString dmcfg.xserverArgs} "$@"
   '';
 
   Xsetup = pkgs.writeScript "Xsetup" ''
diff --git a/nixos/modules/services/x11/display-managers/slim.nix b/nixos/modules/services/x11/display-managers/slim.nix
index ca2ae1a4772..68acde85b5d 100644
--- a/nixos/modules/services/x11/display-managers/slim.nix
+++ b/nixos/modules/services/x11/display-managers/slim.nix
@@ -12,7 +12,7 @@ let
     ''
       xauth_path ${dmcfg.xauthBin}
       default_xserver ${dmcfg.xserverBin}
-      xserver_arguments ${dmcfg.xserverArgs}
+      xserver_arguments ${toString dmcfg.xserverArgs}
       sessiondir ${dmcfg.session.desktops}
       login_cmd exec ${pkgs.stdenv.shell} ${dmcfg.session.script} "%session"
       halt_cmd ${config.systemd.package}/sbin/shutdown -h now
diff --git a/nixos/modules/virtualisation/containers.nix b/nixos/modules/virtualisation/containers.nix
index cfc1065b729..a532696d03a 100644
--- a/nixos/modules/virtualisation/containers.nix
+++ b/nixos/modules/virtualisation/containers.nix
@@ -667,7 +667,7 @@ in
         ${cfg.localAddress} ${name}.containers
       '') config.containers);
 
-    networking.dhcpcd.denyInterfaces = [ "ve-*" ];
+    networking.dhcpcd.denyInterfaces = [ "ve-*" "vb-*" ];
 
     environment.systemPackages = [ pkgs.nixos-container ];
   });
diff --git a/nixos/modules/virtualisation/lxcfs.nix b/nixos/modules/virtualisation/lxcfs.nix
new file mode 100644
index 00000000000..48462dc66da
--- /dev/null
+++ b/nixos/modules/virtualisation/lxcfs.nix
@@ -0,0 +1,49 @@
+# LXC Configuration
+
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+  cfg = config.virtualisation.lxc.lxcfs;
+in {
+  meta.maintainers = [ maintainers.mic92 ];
+
+  ###### interface
+  options.virtualisation.lxc.lxcfs = {
+    enable =
+      mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          This enables LXCFS, a FUSE filesystem for LXC.
+          To use lxcfs in include the following configuration in your
+          container configuration:
+          <code>
+            virtualisation.lxc.defaultConfig = "lxc.include = ''${pkgs.lxcfs}/share/lxc/config/common.conf.d/00-lxcfs.conf";
+          </code>
+        '';
+      };
+  };
+
+  ###### implementation
+  config = mkIf cfg.enable {
+    services.cgmanager.enable = true;
+
+    systemd.services.lxcfs = {
+      description = "FUSE filesystem for LXC";
+      wantedBy = [ "multi-user.target" ];
+      requires = [ "cgmanager.service" ];
+      after = [ "cgmanager.service" ];
+      before = [ "lxc.service" ];
+      restartIfChanged = false;
+      serviceConfig = {
+        ExecStartPre="${pkgs.coreutils}/bin/mkdir -p /var/lib/lxcfs";
+        ExecStart="${pkgs.lxcfs}/bin/lxcfs /var/lib/lxcfs";
+        ExecStopPost="-${pkgs.fuse}/bin/fusermount -u /var/lib/lxcfs";
+        KillMode="process";
+        Restart="on-failure";
+      };
+    };
+  };
+}
diff --git a/nixos/tests/blivet.nix b/nixos/tests/blivet.nix
index a7b836ce99a..2adc2ee1eee 100644
--- a/nixos/tests/blivet.nix
+++ b/nixos/tests/blivet.nix
@@ -1,4 +1,4 @@
-import ./make-test.nix ({ pkgs, ... }: with pkgs.pythonPackages; rec {
+import ./make-test.nix ({ pkgs, ... }: with pkgs.python2Packages; rec {
   name = "blivet";
   meta = with pkgs.stdenv.lib.maintainers; {
     maintainers = [ aszlig ];
diff --git a/nixos/tests/ecryptfs.nix b/nixos/tests/ecryptfs.nix
index db800c7bb2c..041be0f5a62 100644
--- a/nixos/tests/ecryptfs.nix
+++ b/nixos/tests/ecryptfs.nix
@@ -21,13 +21,13 @@ import ./make-test.nix ({ pkgs, ... }:
     $machine->log("ecryptfs-migrate-home said: $out");
 
     # Log alice in (ecryptfs passwhrase is wrapped during first login)
-    $machine->sleep(2); # urgh: wait for username prompt
+    $machine->waitUntilTTYMatches(1, "login: ");
     $machine->sendChars("alice\n");
-    $machine->sleep(1);
+    $machine->waitUntilTTYMatches(1, "Password: ");
     $machine->sendChars("foobar\n");
-    $machine->sleep(2);
+    $machine->waitUntilTTYMatches(1, "alice\@machine");
     $machine->sendChars("logout\n");
-    $machine->sleep(2);
+    $machine->waitUntilTTYMatches(1, "login: ");
 
     # Why do I need to do this??
     $machine->succeed("su alice -c ecryptfs-umount-private || true");
@@ -39,10 +39,11 @@ import ./make-test.nix ({ pkgs, ... }:
     $machine->log("keyctl unlink said: " . $out);
 
     # Log alice again
+    $machine->waitUntilTTYMatches(1, "login: ");
     $machine->sendChars("alice\n");
-    $machine->sleep(1);
+    $machine->waitUntilTTYMatches(1, "Password: ");
     $machine->sendChars("foobar\n");
-    $machine->sleep(2);
+    $machine->waitUntilTTYMatches(1, "alice\@machine");
 
     # Create some files in encrypted home
     $machine->succeed("su alice -c 'touch ~alice/a'");
@@ -50,7 +51,7 @@ import ./make-test.nix ({ pkgs, ... }:
 
     # Logout
     $machine->sendChars("logout\n");
-    $machine->sleep(2);
+    $machine->waitUntilTTYMatches(1, "login: ");
 
     # Why do I need to do this??
     $machine->succeed("su alice -c ecryptfs-umount-private || true");
@@ -62,10 +63,11 @@ import ./make-test.nix ({ pkgs, ... }:
     $machine->succeed("su alice -c 'test \! -f ~alice/b'");
 
     # Log alice once more
+    $machine->waitUntilTTYMatches(1, "login: ");
     $machine->sendChars("alice\n");
-    $machine->sleep(1);
+    $machine->waitUntilTTYMatches(1, "Password: ");
     $machine->sendChars("foobar\n");
-    $machine->sleep(2);
+    $machine->waitUntilTTYMatches(1, "alice\@machine");
 
     # Check that the files are there
     $machine->sleep(1);
@@ -77,5 +79,6 @@ import ./make-test.nix ({ pkgs, ... }:
     $machine->succeed("su alice -c 'ls -lh ~alice/'");
 
     $machine->sendChars("logout\n");
+    $machine->waitUntilTTYMatches(1, "login: ");
   '';
 })
diff --git a/nixos/tests/ipfs.nix b/nixos/tests/ipfs.nix
new file mode 100644
index 00000000000..92d742e4f37
--- /dev/null
+++ b/nixos/tests/ipfs.nix
@@ -0,0 +1,37 @@
+
+import ./make-test.nix ({ pkgs, ...} : {
+  name = "ipfs";
+  meta = with pkgs.stdenv.lib.maintainers; {
+    maintainers = [ mguentner ];
+  };
+
+  nodes = {
+    adder =
+      { config, pkgs, ... }:
+      {
+        services.ipfs = {
+          enable = true;
+          gatewayAddress = "/ip4/127.0.0.1/tcp/2323";
+          apiAddress = "/ip4/127.0.0.1/tcp/2324";
+        };
+      };
+    getter =
+      { config, pkgs, ... }:
+      {
+         services.ipfs.enable = true;
+      };
+  };
+
+  testScript = ''
+    startAll;
+    $adder->waitForUnit("ipfs");
+    # * => needs ipfs dht (internet)
+    # $getter->waitForUnit("ipfs");
+    $adder->waitUntilSucceeds("ipfs --api /ip4/127.0.0.1/tcp/2324 id");
+    $adder->mustSucceed("([[ -n '$(ipfs --api /ip4/127.0.0.1/tcp/2324 config Addresses.gatewayAddress | grep /ip4/127.0.0.1/tcp/2323)' ]])");
+    # * $getter->waitUntilSucceeds("ipfs --api /ip4/127.0.0.1/tcp/5001 id");
+    # * my $ipfsHash = $adder->mustSucceed("echo fnord | ipfs --api /ip4/127.0.0.1/tcp/2324 add | cut -d' ' -f2");
+    $adder->mustSucceed("([[ -n '$(echo fnord | ipfs --api /ip4/127.0.0.1/tcp/2324 add | grep added)' ]])");
+    # * $getter->mustSucceed("ipfs --api /ip4/127.0.0.1/tcp/5001 cat $ipfsHash");
+    '';
+})
diff --git a/nixos/tests/login.nix b/nixos/tests/login.nix
index e793d89567b..a6a460fb0a7 100644
--- a/nixos/tests/login.nix
+++ b/nixos/tests/login.nix
@@ -33,10 +33,11 @@ import ./make-test.nix ({ pkgs, latestKernel ? false, ... }:
 
       # Log in as alice on a virtual console.
       subtest "virtual console login", sub {
-          $machine->sleep(2); # urgh: wait for username prompt
+          $machine->waitUntilTTYMatches(2, "login: ");
           $machine->sendChars("alice\n");
+          $machine->waitUntilTTYMatches(2, "login: alice");
           $machine->waitUntilSucceeds("pgrep login");
-          $machine->sleep(2); # urgh: wait for `Password:'
+          $machine->waitUntilTTYMatches(2, "Password: ");
           $machine->sendChars("foobar\n");
           $machine->waitUntilSucceeds("pgrep -u alice bash");
           $machine->sendChars("touch done\n");