diff --git a/initrd/dracut/module-setup.sh b/initrd/dracut/module-setup.sh index 61de7ce..41ab0b2 100755 --- a/initrd/dracut/module-setup.sh +++ b/initrd/dracut/module-setup.sh @@ -6,21 +6,25 @@ _get_backend() { - rootfs="$(awk '$2 == "/" && $3 == "zfs" {print $1; exit 1}' /etc/mtab)" - [ -z "$rootfs" ] && return 1 + OIFS="$IFS" + IFS=' +' + rootfses="$(awk '$2 ~ "^(/|/etc|/bin|/lib|/lib??|/libx32|/usr)$" && $3 == "zfs" {print $1}' /etc/mtab)" + [ -z "$rootfses" ] && IFS="$OIFS" && return 1 - eroot="$(zfs get encryptionroot -Ho value "$rootfs")" - [ -z "$eroot" ] || [ "$eroot" = "-" ] && return 1 + eroots="$(zfs get encryptionroot -Ho value $rootfses | sort -u | grep -vFxe '' -e '-')" + [ -z "$eroots" ] && IFS="$OIFS" && return 1 + backends="$(zfs-tpm-list -H $eroots | cut -f2 | sort -u)" + [ -z "$backends" ] && IFS="$OIFS" && return 1 - backend="$(zfs-tpm-list -H "$eroot" | cut -f2)" - [ -n "$backend" ] - return + IFS="$OIFS" + return 0 } _install_tpm2() { inst_binary zfs-tpm2-load-key - # shellcheck disable=SC2046 + # shellcheck disable=SC2046 inst_library $(find /usr/lib -name 'libtss2-tcti*.so*') # TODO: there's got to be a better way™! command -v tpm2_dictionarylockout > /dev/null && inst_binary tpm2_dictionarylockout } @@ -35,17 +39,19 @@ _install_tpm1x() { check() { command -v zfs-tpm-list > /dev/null || return 1 - # shellcheck disable=SC2154 - if [ -n "$hostonly" ]; then + # shellcheck disable=SC2154 + if [ -n "$hostonly" ]; then _get_backend || return - [ "$backend" = "TPM2" ] && command -v zfs-tpm2-load-key > /dev/null && return 0 - [ "$backend" = "TPM1.X" ] && command -v zfs-tpm1x-load-key > /dev/null && return 0 + for backend in $backends; do + [ "$backend" = "TPM2" ] && command -v zfs-tpm2-load-key > /dev/null && return 0 + [ "$backend" = "TPM1.X" ] && command -v zfs-tpm1x-load-key > /dev/null && return 0 + done return 1 - fi + fi - return 0 + return 0 } @@ -65,8 +71,10 @@ install() { if [ -n "$hostonly" ]; then _get_backend - [ "$backend" = "TPM2" ] && _install_tpm2 - [ "$backend" = "TPM1.X" ] && _install_tpm1x + for backend in $backends; do + [ "$backend" = "TPM2" ] && _install_tpm2 + [ "$backend" = "TPM1.X" ] && _install_tpm1x + done else command -v zfs-tpm2-load-key > /dev/null && _install_tpm2 command -v zfs-tpm1x-load-key > /dev/null && _install_tpm1x diff --git a/initrd/dracut/tzpfms-load-key.sh b/initrd/dracut/tzpfms-load-key.sh index 1381907..b0e2467 100755 --- a/initrd/dracut/tzpfms-load-key.sh +++ b/initrd/dracut/tzpfms-load-key.sh @@ -20,6 +20,8 @@ rootfstype="${rootfstype:=$(getarg rootfstype=)}" TZPFMS_TPM1X="$(getarg TZPFMS_TPM1X=)" [ -z "$TZPFMS_TPM1X" ] || export TZPFMS_TPM1X +getarg 0 quiet && quiet=y + # There is a race between the zpool import and the pre-mount hooks, so we wait for a pool to be imported while [ "$(zpool list -H)" = "" ]; do @@ -38,25 +40,57 @@ fi WITH_PROMPTABLE_TTY{< /dev/console > /dev/console 2>&1} +# tzpfms_for_relevant_root_children DATASET EXEC +# Runs "EXEC dataset mountpoint" for all children of DATASET that are needed for system bringup +# Used by zfs-nonroot-necessities.service and friends, too! +tzpfms_for_relevant_root_children() { + dataset="${1}" + exec="${2}" + + zfs list -t filesystem -Ho name,mountpoint,canmount -r "${dataset}" | + ( + _ret=0 + while IFS="${TAB}" read -r dataset mountpoint canmount; do + [ "$canmount" != "on" ] && continue + + case "$mountpoint" in + /etc|/bin|/lib|/lib??|/libx32|/usr) + # If these aren't mounted we may not be able to get to the real init at all, or pollute the dataset holding the rootfs + "${exec}" "${dataset}" "${mountpoint}" || _ret=$? + ;; + *) + # Up to the real init to remount everything else it might need + ;; + esac + done + exit "${_ret}" + ) +} + +tzpfms_load() + # Match this sexion to i-t/zfs-patch.sh + if command -v zfs-tpm2-load-key > /dev/null && [ -n "$(zfs-tpm-list -Hub TPM2 "$1")" ]; then + with_promptable_tty zfs-tpm2-load-key "$1" + return + fi + + if command -v zfs-tpm1x-load-key > /dev/null && [ -n "$(zfs-tpm-list -Hub TPM1.X "$1")" ]; then + POTENTIALLY_START_TCSD{ss -ltO, > /dev/console 2>&1} + with_promptable_tty zfs-tpm1x-load-key "$1"; err="$?" + POTENTIALLY_KILL_TCSD{} + return "$err" + fi +} + # If pool encryption is active and the zfs command understands '-o encryption' if [ "$(zpool list -H -o feature@encryption "${BOOTFS%%/*}")" = "active" ]; then ENCRYPTIONROOT="$(zfs get -H -o value encryptionroot "$BOOTFS")" if ! [ "${ENCRYPTIONROOT}" = "-" ]; then - # Match this sexion to i-t/zfs-patch.sh - if command -v zfs-tpm2-load-key > /dev/null && [ -n "$(zfs-tpm-list -Hub TPM2 "$ENCRYPTIONROOT")" ]; then - with_promptable_tty zfs-tpm2-load-key "$ENCRYPTIONROOT" - exit - fi - - if command -v zfs-tpm1x-load-key > /dev/null && [ -n "$(zfs-tpm-list -Hub TPM1.X "$ENCRYPTIONROOT")" ]; then - POTENTIALLY_START_TCSD{ss -ltO, > /dev/console 2>&1} - with_promptable_tty zfs-tpm1x-load-key "$ENCRYPTIONROOT"; err="$?" - POTENTIALLY_KILL_TCSD{} - exit "$err" - fi - + tzpfms_load "$ENCRYPTIONROOT" || exit # Fall through to zfs-dracut's zfs-load-key.sh fi + + tzpfms_for_relevant_root_children "$ENCRYPTIONROOT" tzpfms_load || exit fi