Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request ZFS/LUKS passwords via Plymouth #88789

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 6 additions & 34 deletions nixos/modules/system/boot/luksroot.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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."
Expand All @@ -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;

Expand Down Expand Up @@ -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
Expand Down
24 changes: 19 additions & 5 deletions nixos/modules/system/boot/plymouth.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will break with #73795, since fontconfig now includes configuration from ${fontconfig}/etc/fonts/conf.d, which is not in allowed references:

output '/nix/store/4gkpl38kjw3qskfz5gy7f74ahlps04c7-extra-utils' is not allowed to refer to the following paths:
  /nix/store/whh21mr17whyq1mm2h7lzj98ixi4w3ps-fontconfig-2.13.92

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

guess i'll have to actually build my own fontconfig xml..

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also need to use the versioned fonts.conf path since our fontconfig no longer uses the unversioned one.

Something like this might work:

--- a/nixos/modules/system/boot/plymouth.nix
+++ b/nixos/modules/system/boot/plymouth.nix
@@ -105,7 +105,13 @@ in
     systemd.services.systemd-ask-password-plymouth.wantedBy = ["multi-user.target"];
     systemd.paths.systemd-ask-password-plymouth.wantedBy = ["multi-user.target"];
 
-    boot.initrd.extraUtilsCommands = ''
+    boot.initrd.extraUtilsCommands = let
+      fonts_conf = (pkgs.makeFontsConf {
+        fontDirectories = [];
+      }).override {
+        dejavu_fonts.minimal = "/usr/share/fonts";
+      };
+    in ''
       copy_bin_and_libs ${pkgs.plymouth}/bin/plymouthd
       copy_bin_and_libs ${pkgs.plymouth}/bin/plymouth
 
@@ -135,13 +141,15 @@ in
       cp ${cfg.logo} $out/share/plymouth/logo.png
 
       mkdir -p $out/usr/share/fonts/truetype
-      mkdir -p $out/etc/fonts/2.11/conf.d
+      mkdir -p $out/etc/fonts/${pkgs.fontconfig.configVersion}/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@<dir>${pkgs.dejavu_fonts.minimal}</dir>@<dir>/usr/share/fonts</dir>@g' $out/etc/fonts/2.11/fonts.conf
+      cp ${pkgs.fontconfig.out}/share/fontconfig/conf.avail/60-latin.conf $out/etc/fonts/${pkgs.fontconfig.configVersion}/conf.d
+      cp ${fonts_conf} $out/etc/fonts/${pkgs.fontconfig.configVersion}/fonts.conf
+
+      # Do not include default config files since they are not available in stage-1.
+      sed -i 's@<include>${pkgs.fontconfig.out}/etc/fonts/conf.d</include>@@g' $out/etc/fonts/${pkgs.fontconfig.configVersion}/fonts.conf
     '';
 
     boot.initrd.extraUtilsCommandsTest = ''

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In #95358, we have stopped using versioned configs altogether.

sed -i 's@<dir>${pkgs.dejavu_fonts.minimal}</dir>@<dir>/usr/share/fonts</dir>@g' $out/etc/fonts/2.11/fonts.conf
'';

boot.initrd.extraUtilsCommandsTest = ''
Expand All @@ -143,17 +152,22 @@ 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 ''
mkdir -p /etc/plymouth
boot.initrd.preLogCommands = ''
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

askPassword() {
plymouth ask-for-password --prompt="$1"
}
'';

boot.initrd.postMountCommands = ''
Expand Down
26 changes: 21 additions & 5 deletions nixos/modules/system/boot/stage-1-init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -116,6 +111,23 @@ source @earlyMountScript@
mkdir -p /tmp
mkfifo /tmp/stage-1-init.log.fifo
logOutFd=8 && logErrFd=9

# askPassword <prompt>
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
Expand All @@ -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
Expand Down
10 changes: 9 additions & 1 deletion nixos/modules/system/boot/stage-1.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
9 changes: 2 additions & 7 deletions nixos/modules/tasks/filesystems/bcachefs.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
25 changes: 23 additions & 2 deletions nixos/modules/tasks/filesystems/zfs.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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));
};
Expand Down