From c7efbe10a64ebafeb6e4bb28f1e04633b39fac6d Mon Sep 17 00:00:00 2001 From: Puck Meerburg Date: Sun, 17 May 2020 17:23:51 +0000 Subject: [PATCH 1/6] nixos/stage-1: Add helper function for password requests When using Plymouth, it's possible to have a graphical interface for requesting passwords and showing boot info. To accomodate this, we add a hook that allows other stage-1 code to seamlessly use this when available. --- nixos/modules/system/boot/stage-1-init.sh | 26 ++++++++++++++++++----- nixos/modules/system/boot/stage-1.nix | 10 ++++++++- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/nixos/modules/system/boot/stage-1-init.sh b/nixos/modules/system/boot/stage-1-init.sh index 607aec87f01e5..b97a5035f41a7 100644 --- a/nixos/modules/system/boot/stage-1-init.sh +++ b/nixos/modules/system/boot/stage-1-init.sh @@ -62,11 +62,6 @@ EOF trap 'fail' 0 -# Print a greeting. -echo -echo "<<< NixOS Stage 1 >>>" -echo - # Make several required directories. mkdir -p /etc/udev touch /etc/fstab # to shut up mount @@ -116,6 +111,23 @@ source @earlyMountScript@ mkdir -p /tmp mkfifo /tmp/stage-1-init.log.fifo logOutFd=8 && logErrFd=9 + +# askPassword +askPassword() { + # Ensure that we don't reset the echo flag. + curStatus=$(stty -g) + stty -echo + + printf "%s" "$1" >&2 + IFS= read -r password + printf "\n" >&2 + + stty "$curStatus" + printf "%s" "$password" +} + +@preLogCommands@ + eval "exec $logOutFd>&1 $logErrFd>&2" if test -w /dev/kmsg; then tee -i < /tmp/stage-1-init.log.fifo /proc/self/fd/"$logOutFd" | while read -r line; do @@ -129,6 +141,10 @@ else fi exec > /tmp/stage-1-init.log.fifo 2>&1 +# Print a greeting. +echo +echo -e "\e[1;3m<<< NixOS Stage 1 >>>\e[0m" +echo # Process the kernel command line. export stage2Init=/init diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix index dfd158e2d75f4..dbc757dcea73a 100644 --- a/nixos/modules/system/boot/stage-1.nix +++ b/nixos/modules/system/boot/stage-1.nix @@ -280,7 +280,7 @@ let inherit (config.system.build) earlyMountScript; inherit (config.boot.initrd) checkJournalingFS - preLVMCommands preDeviceCommands postDeviceCommands postMountCommands preFailCommands kernelModules; + preLVMCommands preLogCommands preDeviceCommands postDeviceCommands postMountCommands preFailCommands kernelModules; resumeDevices = map (sd: if sd ? device then sd.device else "/dev/disk/by-label/${sd.label}") (filter (sd: hasPrefix "/dev/" sd.device && !sd.randomEncryption.enable @@ -438,6 +438,14 @@ in ''; }; + boot.initrd.preLogCommands = mkOption { + default = ""; + type = types.lines; + description = '' + Shell commands to be executed immediately before setting up logging. + ''; + }; + boot.initrd.preDeviceCommands = mkOption { default = ""; type = types.lines; From ef0867ec6503a8dd580d84ba276f3db9fe220278 Mon Sep 17 00:00:00 2001 From: Puck Meerburg Date: Sun, 17 May 2020 17:29:47 +0000 Subject: [PATCH 2/6] nixos/zfs: use stage-1 hooks for requesting passphrases --- nixos/modules/tasks/filesystems/zfs.nix | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/nixos/modules/tasks/filesystems/zfs.nix b/nixos/modules/tasks/filesystems/zfs.nix index 43347161a84c6..bfa9b10077a0f 100644 --- a/nixos/modules/tasks/filesystems/zfs.nix +++ b/nixos/modules/tasks/filesystems/zfs.nix @@ -421,8 +421,29 @@ in fi poolImported "${pool}" || poolImport "${pool}" # Try one last time, e.g. to import a degraded pool. fi - ${lib.optionalString cfgZfs.requestEncryptionCredentials '' - zfs load-key -a + ${optionalString cfgZfs.requestEncryptionCredentials '' + zfs list -r -H -o encryptionroot,keystatus,keylocation "${pool}" | sort | uniq | while IFS=" " read encryptionroot keystatus keylocation; do + if [ "$keystatus" != "unavailable" -o "$keylocation" == "none" ]; then + continue + fi + + if [ "$keylocation" != "prompt" ]; then + "${packages.zfsUser}/bin/zfs" load-key "$encryptionroot" || die "Failed to load key for $encryptionroot" + continue + fi + + success= + for i in $(seq 1 3); do + if askPassword "Enter key for $encryptionroot: " | zfs load-key "$encryptionroot"; then + success=1 + break + fi + done + + if [ -z "$success" ]; then + die "Failed to load key for $encryptionroot" + fi + done ''} '') rootPools)); }; From 74e90f349898670dbbb7ab3efbebb12802c059e0 Mon Sep 17 00:00:00 2001 From: Puck Meerburg Date: Sun, 17 May 2020 17:27:07 +0000 Subject: [PATCH 3/6] nixos/luksroot: Use new stage-1 password hooks This allows for entering passwords inside plymouth. --- nixos/modules/system/boot/luksroot.nix | 40 ++++---------------------- 1 file changed, 6 insertions(+), 34 deletions(-) diff --git a/nixos/modules/system/boot/luksroot.nix b/nixos/modules/system/boot/luksroot.nix index 31f1e22cda32c..92ba79b2bed33 100644 --- a/nixos/modules/system/boot/luksroot.nix +++ b/nixos/modules/system/boot/luksroot.nix @@ -157,19 +157,15 @@ let local passphrase while true; do - echo -n "Passphrase for ${device}: " passphrase= while true; do if [ -e /crypt-ramfs/passphrase ]; then - echo "reused" + echo "Passphrase for ${device}: reused" passphrase=$(cat /crypt-ramfs/passphrase) break else - # ask cryptsetup-askpass echo -n "${device}" > /crypt-ramfs/device - - # and try reading it from /dev/console with a timeout - IFS= read -t 1 -r passphrase + passphrase="$(askPassword "Passphrase for ${device}: ")" if [ -n "$passphrase" ]; then ${if luks.reusePassphrases then '' # remember it for the next device @@ -253,9 +249,7 @@ let for try in $(seq 3); do ${optionalString yubikey.twoFactor '' - echo -n "Enter two-factor passphrase: " - read -r k_user - echo + k_user="$(askPassword "Enter two-factor passphrase: ")" ''} if [ ! -z "$k_user" ]; then @@ -336,16 +330,15 @@ let 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" + echo "PIN for GPG Card associated with device ${device}: reused" pin=$(cat /crypt-ramfs/passphrase) break else # and try reading it from /dev/console with a timeout - IFS= read -t 1 -r pin + pin="$(askPassword "PIN for GPG Card associated with device ${device}: ")" if [ -n "$pin" ]; then ${if luks.reusePassphrases then '' # remember it for the next device @@ -396,8 +389,7 @@ let ${if fido2.passwordLess then '' export passphrase="" '' else '' - read -rsp "FIDO2 salt for ${device}: " passphrase - echo + passphrase="$(askPassword "FIDO2 salt for ${device}: ")" ''} ${optionalString (lib.versionOlder kernelPackages.kernel.version "5.4") '' echo "On systems with Linux Kernel < 5.4, it might take a while to initialize the CRNG, you might want to use linuxPackages_latest." @@ -419,24 +411,6 @@ let ''} ''; - askPass = pkgs.writeScriptBin "cryptsetup-askpass" '' - #!/bin/sh - - ${commonFunctions} - - while true; do - wait_target "luks" /crypt-ramfs/device 10 "LUKS to request a passphrase" || die "Passphrase is not requested now" - device=$(cat /crypt-ramfs/device) - - echo -n "Passphrase for $device: " - IFS= read -rs passphrase - echo - - rm /crypt-ramfs/device - echo -n "$passphrase" > /crypt-ramfs/passphrase - done - ''; - preLVM = filterAttrs (n: v: v.preLVM) luks.devices; postLVM = filterAttrs (n: v: !v.preLVM) luks.devices; @@ -797,8 +771,6 @@ in # copy the cryptsetup binary and it's dependencies boot.initrd.extraUtilsCommands = '' copy_bin_and_libs ${pkgs.cryptsetup}/bin/cryptsetup - copy_bin_and_libs ${askPass}/bin/cryptsetup-askpass - sed -i s,/bin/sh,$out/bin/sh, $out/bin/cryptsetup-askpass ${optionalString luks.yubikeySupport '' copy_bin_and_libs ${pkgs.yubikey-personalization}/bin/ykchalresp From 329b9b989699db7820f42da177978d11eb70493a Mon Sep 17 00:00:00 2001 From: Puck Meerburg Date: Sun, 24 May 2020 14:49:33 +0000 Subject: [PATCH 4/6] nixos/plymouth: Use password hook This loads Plymouth way earlier in the boot process, and sets it up so password prompts are processed by Plymouth, instead of the terminal. --- nixos/modules/system/boot/plymouth.nix | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/nixos/modules/system/boot/plymouth.nix b/nixos/modules/system/boot/plymouth.nix index 23fce22366d8e..74eb2668653fa 100644 --- a/nixos/modules/system/boot/plymouth.nix +++ b/nixos/modules/system/boot/plymouth.nix @@ -143,8 +143,7 @@ in sed -i '/loginctl/d' $out/71-seat.rules ''; - # We use `mkAfter` to ensure that LUKS password prompt would be shown earlier than the splash screen. - boot.initrd.preLVMCommands = mkAfter '' + boot.initrd.preLogCommands = '' mkdir -p /etc/plymouth ln -s ${configFile} /etc/plymouth/plymouthd.conf ln -s $extraUtils/share/plymouth/plymouthd.defaults /etc/plymouth/plymouthd.defaults @@ -154,6 +153,10 @@ in plymouthd --mode=boot --pid-file=/run/plymouth/pid --attach-to-session plymouth show-splash + + askPassword() { + plymouth ask-for-password --prompt="$1" + } ''; boot.initrd.postMountCommands = '' From 70f8ca8da527b835f407ac0976786124f6ea0719 Mon Sep 17 00:00:00 2001 From: Puck Meerburg Date: Sun, 24 May 2020 14:49:33 +0000 Subject: [PATCH 5/6] nixos/plymouth: Include label module and fonts To show text, Plymouth needs the label plugin. We also copy in both Cantarell and DejaVu Sans, as these are used by the default Plymouth themes. --- nixos/modules/system/boot/plymouth.nix | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/nixos/modules/system/boot/plymouth.nix b/nixos/modules/system/boot/plymouth.nix index 74eb2668653fa..d748cab1c463b 100644 --- a/nixos/modules/system/boot/plymouth.nix +++ b/nixos/modules/system/boot/plymouth.nix @@ -111,7 +111,7 @@ in mkdir -p $out/lib/plymouth/renderers # module might come from a theme - cp ${themesEnv}/lib/plymouth/{text,details,$moduleName}.so $out/lib/plymouth + cp ${themesEnv}/lib/plymouth/{text,details,label,$moduleName}.so $out/lib/plymouth cp ${plymouth}/lib/plymouth/renderers/{drm,frame-buffer}.so $out/lib/plymouth/renderers mkdir -p $out/share/plymouth/themes @@ -120,7 +120,7 @@ in # copy themes into working directory for patching mkdir themes # use -L to copy the directories proper, not the symlinks to them - cp -r -L ${themesEnv}/share/plymouth/themes/{text,details,${cfg.theme}} themes + cp -r -L ${themesEnv}/share/plymouth/themes/{text,details,spinner,${cfg.theme}} themes # patch out any attempted references to the theme or plymouth's themes directory chmod -R +w themes @@ -131,6 +131,15 @@ in cp -r themes/* $out/share/plymouth/themes cp ${cfg.logo} $out/share/plymouth/logo.png + + mkdir -p $out/usr/share/fonts/truetype + mkdir -p $out/etc/fonts/2.11/conf.d + cp -r ${pkgs.cantarell-fonts}/share/fonts/cantarell/Cantarell-{Thin,Regular}.otf $out/usr/share/fonts/truetype + cp -r ${pkgs.dejavu_fonts.minimal}/share/fonts/truetype/DejaVuSans.ttf $out/usr/share/fonts/truetype + + cp ${pkgs.fontconfig.out}/share/fontconfig/conf.avail/60-latin.conf $out/etc/fonts/2.11/conf.d + cp ${pkgs.fontconfig.out}/etc/fonts/fonts.conf $out/etc/fonts/2.11 + sed -i 's@${pkgs.dejavu_fonts.minimal}@/usr/share/fonts@g' $out/etc/fonts/2.11/fonts.conf ''; boot.initrd.extraUtilsCommandsTest = '' @@ -144,12 +153,14 @@ in ''; boot.initrd.preLogCommands = '' - mkdir -p /etc/plymouth + mkdir -p /etc/plymouth /usr/share ln -s ${configFile} /etc/plymouth/plymouthd.conf ln -s $extraUtils/share/plymouth/plymouthd.defaults /etc/plymouth/plymouthd.defaults ln -s $extraUtils/share/plymouth/logo.png /etc/plymouth/logo.png ln -s $extraUtils/share/plymouth/themes /etc/plymouth/themes ln -s $extraUtils/lib/plymouth /etc/plymouth/plugins + ln -s $extraUtils/etc/fonts /etc/fonts + ln -s $extraUtils/usr/share/fonts /usr/share/fonts plymouthd --mode=boot --pid-file=/run/plymouth/pid --attach-to-session plymouth show-splash From e07fb72e4607adac7642283e188e6ad4b8d06979 Mon Sep 17 00:00:00 2001 From: Puck Meerburg Date: Mon, 25 May 2020 09:58:32 +0000 Subject: [PATCH 6/6] nixos/bcachefs: Use password hook --- nixos/modules/tasks/filesystems/bcachefs.nix | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/nixos/modules/tasks/filesystems/bcachefs.nix b/nixos/modules/tasks/filesystems/bcachefs.nix index 5fda24adb9782..806d2c25a5b63 100644 --- a/nixos/modules/tasks/filesystems/bcachefs.nix +++ b/nixos/modules/tasks/filesystems/bcachefs.nix @@ -7,18 +7,13 @@ let bootFs = filterAttrs (n: fs: (fs.fsType == "bcachefs") && (utils.fsNeededForBoot fs)) config.fileSystems; commonFunctions = '' - prompt() { - local name="$1" - printf "enter passphrase for $name: " - } tryUnlock() { local name="$1" local path="$2" if bcachefs unlock -c $path > /dev/null 2> /dev/null; then # test for encryption - prompt $name - until bcachefs unlock $path 2> /dev/null; do # repeat until sucessfully unlocked + # repeat until sucessfully unlocked + until askPassword "Enter passphrase for $name: " | bcachefs unlock $path; do printf "unlocking failed!\n" - prompt $name done printf "unlocking successful.\n" fi