Re: [PATCH v2 4/4] initramfs-crypt-hook: add re-encryption recovery

Quirin Gylstorff
2025-02-27T14:37:50Z

On 2/27/25 15:30, Claudius Heine wrote:
> Integrate detection and recovery of power failures while a partition is
> being encrypted.
>
> There are possible scenarios:
> 1. Power-fail happens while the partition is reencrypted:
> - The LUKS header contains `online-reencrypt-v2` and needs to be
> repaired with `cryptsetup repair` before it can continue.
> - Also no resizing of the file system is necessary
> 2. Power-fail happens before the systemd-tpm2 token can be installed
> - The LUKS header does not contain 'systemd-tpm2', thus it needs to be
> registered and the temporary encryption key needs to be removed
>
> In both scenarios the system after the reboot needs to have access to
> the temporary encryption key that was initially used. So using a random
> one, generated via `openssl rand` is not possible. Since it is only a
> temporary key and gets removed after the systemd-tpm2 token was
> installed, a known password can be used.
>
> The list of these scenarios is not complete, there might be other
> instances where a sudden power-fail could be fatal to the system, but
> these where the most obvious and risky ones.
>
> Signed-off-by: Claudius Heine <ch@denx.de>
> ---
> .../files/local-top-complete | 33 +++++++++++++++----
> .../initramfs-crypt-hook_0.6.bb | 5 ++-
> 2 files changed, 29 insertions(+), 9 deletions(-)
>
> diff --git a/recipes-initramfs/initramfs-crypt-hook/files/local-top-complete b/recipes-initramfs/initramfs-crypt-hook/files/local-top-complete
> index 4b6451a..6034175 100644
> --- a/recipes-initramfs/initramfs-crypt-hook/files/local-top-complete
> +++ b/recipes-initramfs/initramfs-crypt-hook/files/local-top-complete
> @@ -72,6 +72,9 @@ reencrypt_existing_partition() {
> reduced_size="$(expr "$part_size_blocks" - 65536 )"
> reduced_size_in_byte="$(expr "$reduced_size" \* 512)"
> reduced_size_in_kb="$(expr "$reduced_size_in_byte" / 1024)K"
> +
> + CRYPTSETUP_PARAMS="--reduce-device-size ${reduce_device_size}k"
> +
> case $partition_fstype in
> ext*)
> # reduce the filesystem and partition by 32M to fit the LUKS header
> @@ -90,14 +93,25 @@ reencrypt_existing_partition() {
> squashfs|swap|erofs|"")
> [ "$debug" = "y" ] && echo "skip disk resize as it is not supported or unnecessary for fstype: '$partition_fstype'"
> ;;
> + luks)
> + # Check if reencrypt was aborted
> + if /usr/sbin/cryptsetup luksDump --batch-mode "$1" \
> + | grep -q "online-reencrypt-v2"; then
> + /usr/sbin/cryptsetup repair --batch-mode "$1" < "$2" || \
> + panic "cryptsetup repair was not successful"
> + fi
> +
> + # already luks partition, don't resize
> + CRYPTSETUP_PARAMS=""
> + ;;
> *)
> panic "cannot resize partition, unsupported fstype: '$partition_fstype'"
> ;;
> esac
> if [ -x /usr/sbin/cryptsetup-reencrypt ]; then
> - /usr/sbin/cryptsetup-reencrypt --new --reduce-device-size "$reduce_device_size"k "$1" < "$2"
> + /usr/sbin/cryptsetup-reencrypt --new ${CRYPTSETUP_PARAMS} "$1" < "$2"
> else
> - /usr/sbin/cryptsetup reencrypt --encrypt --reduce-device-size "$reduce_device_size"k "$1" < "$2"
> + /usr/sbin/cryptsetup reencrypt --encrypt ${CRYPTSETUP_PARAMS} "$1" < "$2"
> fi
> }
>
> @@ -219,7 +233,7 @@ for partition_set in $partition_sets; do
> # If partition is already encrypted, decrypt and continue with next partition:
> decrypted_part=/dev/mapper/"$crypt_mount_name"
> if /usr/sbin/cryptsetup luksDump --batch-mode "$part_device" \
> - | grep -q "luks2"; then
> + | grep -q "systemd-tpm2"; then
This should break encryption with clevis.

> open_tpm2_partition "$part_device" "$crypt_mount_name" "$tpm_device"
>
> # check if we are trying to mount root, set ROOT to decrypted partition:
> @@ -230,6 +244,12 @@ for partition_set in $partition_sets; do
> continue
> fi
>
> + # If partition contains an aborted reencrypt luks header, switch to reencrypt mode:
> + if /usr/sbin/cryptsetup luksDump --batch-mode "${part_device}" \
> + | grep -q "online-reencrypt-v2"; then
> + partition_format="reencrypt"
> + fi
> +
> # If partition should not be encrypted, continue with next partition:
> if [ "$partition_format" = "noencrypt" ]
> then
> @@ -247,10 +267,11 @@ for partition_set in $partition_sets; do
> watchdog_pid=$!
> fi
>
> - # create random password for initial encryption
> - # this will be dropped after reboot
> + # use partuuid of the partition for initial encryption password, this key
> + # will be removed after the reencryption has finished and the TPM2 token is
> + # registered:
> tmp_key=/tmp/"$(basename "$part_device")-lukskey"
> - openssl rand -base64 32 > "$tmp_key"
> + lsblk -no partuuid "$part_device" > "$tmp_key"

This has the security implication that until the tpm key is used the
device is insecure.

Quirin
>
> case "${partition_format}" in
> "reencrypt")
> diff --git a/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.6.bb b/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.6.bb
> index c9a7f89..5e82521 100644
> --- a/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.6.bb
> +++ b/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.6.bb
> @@ -14,7 +14,6 @@ require recipes-initramfs/initramfs-hook/hook.inc
> DEBIAN_DEPENDS .= ", \
> cryptsetup, \
> awk, \
> - openssl, \
> e2fsprogs, \
> tpm2-tools, \
> coreutils, \
> @@ -40,8 +39,8 @@ HOOK_ADD_MODULES = " \
> ecb aes_generic xts"
>
> HOOK_COPY_EXECS = " \
> - openssl mke2fs grep awk expr seq sleep basename uuidparse mountpoint \
> - e2fsck resize2fs cryptsetup cmp \
> + mke2fs grep awk expr seq sleep basename uuidparse mountpoint \
> + e2fsck resize2fs cryptsetup cmp lsblk \
> tpm2_pcrread tpm2_testparms tpm2_flushcontext \
> /usr/lib/*/libgcc_s.so.1"
>