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

Claudius Heine
2025-02-27T15:03:30Z

On 2025-02-27 3:56 pm, Quirin Gylstorff wrote:
>
>
> On 2/27/25 15:46, Claudius Heine wrote:
>> 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.
>
>
> If you set `CRYPT_BACKEND = "clevis" ` in the kas configuration of isar-
> cip-core. You directly use clevis instead of systemd.
>
> https://gitlab.com/cip-project/cip-core/isar-cip-core/-/blob/master/
> recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.6.bb?
> ref_type=heads#L25

I can look into it. I suppose there might be some other marker that can
be used.

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

Also, there is a security implication already with this implementation,
even before applying this patch, that until the device is booted and the
re-encryption process is started, the storage is completely unencrypted
and thus the device is insecure. :P

I assume that the people that actually need to deploy images in factory,
will take care of letting the re-encryption process properly finish.

An in-field the device before the re-encryption process is about the
same insecure as a device in the middle of the reencryption process with
a known key.

regards,
Claudius

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