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

Claudius Heine
2025-02-27T14:46:40Z

Hi Quirin,

On 2025-02-27 3:37 pm, Quirin Gylstorff wrote:
>
>
> 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.

I don't have a test setup for clevis, so any input on how to fix this,
would be great.

>
>>           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.

Yes. As I noted in the commit message.

The other method, I thought about was using the tpm2, where I am
encrypting a known key, like the partuuid with an internal tpm2 key, and
using the resulting encrypted blob as a hexstring for the password.

But I am not very familiar with TPM2 on how to properly do that.

Other options would be to create a password and store it in the TPM2
NVRAM, but that would not be very secure as well.

So any suggestions for improvment here would be great.

regards,
Claudius

>
> 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"
>

--
DENX Software Engineering GmbH, Managing Director: Erika Unter
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-54 Fax: (+49)-8142-66989-80 Email: ch@denx.de