diff mbox series

[3/4] initramfs-crypt-hook: Speedup disk-encryption reencrypt

Message ID 20240712081143.1376952-4-stefan-koch@siemens.com (mailing list archive)
State New
Headers show
Series initramfs-crypt-hook: Speedup disk-encryption reencrypt and other improvements | expand

Commit Message

Stefan Koch July 12, 2024, 8:11 a.m. UTC
- When "CRYPT_FAST_REENCRYPTION" is set to "1" (consider security and
  data reliablity aspects when enabling):
  - shrink partition temporarily to minimum
  - encrypt shrinked partition
  - expand encrypted partition to maximum

Signed-off-by: Stefan Koch <stefan-koch@siemens.com>
---
 .../files/encrypt_partition.env.tmpl          |  1 +
 .../files/encrypt_partition.script            | 50 ++++++++++++++++---
 .../initramfs-crypt-hook_0.2.bb               |  6 ++-
 3 files changed, 49 insertions(+), 8 deletions(-)

Comments

Jan Kiszka July 12, 2024, 9:30 a.m. UTC | #1
On 12.07.24 10:11, Stefan Koch wrote:
> - When "CRYPT_FAST_REENCRYPTION" is set to "1" (consider security and
>   data reliablity aspects when enabling):

Where are they documented?

>   - shrink partition temporarily to minimum
>   - encrypt shrinked partition
>   - expand encrypted partition to maximum

Can't we rather generate a layout that starts small and expands after
encryption?

Jan

> 
> Signed-off-by: Stefan Koch <stefan-koch@siemens.com>
> ---
>  .../files/encrypt_partition.env.tmpl          |  1 +
>  .../files/encrypt_partition.script            | 50 ++++++++++++++++---
>  .../initramfs-crypt-hook_0.2.bb               |  6 ++-
>  3 files changed, 49 insertions(+), 8 deletions(-)
> 
> diff --git a/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.env.tmpl b/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.env.tmpl
> index 72033d1..9f3df4f 100644
> --- a/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.env.tmpl
> +++ b/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.env.tmpl
> @@ -6,3 +6,4 @@ HASH_TYPE="${CRYPT_HASH_TYPE}"
>  KEY_ALGORITHM="${CRYPT_KEY_ALGORITHM}"
>  ENCRYPTION_IS_OPTIONAL="${CRYPT_ENCRYPTION_OPTIONAL}"
>  LOSETUP_PATH="${CRYPT_LOSETUP_PATH}"
> +FAST_REENCRYPTION="${CRYPT_FAST_REENCRYPTION}"
> diff --git a/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.script b/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.script
> index f943aea..e768b54 100644
> --- a/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.script
> +++ b/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.script
> @@ -62,13 +62,16 @@ service_watchdog() {
>  }
>  
>  reencrypt_existing_partition() {
> +	reencrypt_device="$1"
>  	part_size_blocks="$(cat /sys/class/block/"$(awk -v dev="$1" 'BEGIN{split(dev,a,"/"); print a[3]}' )"/size)"
> -	# reduce the filesystem and partition by 32M to fit the LUKS header
> +	part_size_in_kb="$(expr "$part_size_blocks" / 2)" # blocksize 512 byte
> +
>  	partition_fstype=$(get_fstype "${1}")
> +	# reduce the filesystem and partition by 32M to fit the LUKS header
>  	reduce_device_size=32768
> -	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"
> +	reduce_device_size_blocks="$(expr "$reduce_device_size" \* 2)" # 512 byte blocks
> +	reduced_size="$(expr "$part_size_blocks" - "$reduce_device_size_blocks" )"
> +	reduced_size_in_kb="$(expr "$reduced_size" / 2)" # blocksize 512 byte
>  	case $partition_fstype in
>  	ext*)
>  		# reduce the filesystem and partition by 32M to fit the LUKS header
> @@ -84,9 +87,31 @@ EOF
>  		if ! cryptsetup luksUUID "$1" &> /dev/null; then
>  			e2fsck -p -f "$1"
>  		fi
> -		if ! resize2fs "$1" "${reduced_size_in_kb}"; then
> +		# shrink partition temporarily to minimum
> +		min_size_fsblocks="$(resize2fs "$1" -P | awk -F ": " '{ print $2 }')"
> +		if [ "$FAST_REENCRYPTION" = "1" ] && loop_device="$("$LOSETUP_PATH" -f)" && [ -n "$min_size_fsblocks" ]; then
> +			# set encrypted size for expanding step
> +			encrypted_size_in_kb="$reduced_size_in_kb"
> +			# minimum partition size
> +			min_size_in_kb="$(expr "$min_size_fsblocks" \* 4)" # blocksize 4096 byte
> +			# shrinked partition size (reduce_size + minimum partition size)
> +			reduced_size_in_kb="$(expr "$reduce_device_size" + "$min_size_in_kb")"
> +			# set loop device as reencrypt device
> +			reencrypt_device="$loop_device"
> +		else
> +			# continue with default reencryption in failure case
> +			FAST_REENCRYPTION="0"
> +		fi
> +
> +		if ! resize2fs "$1" "${reduced_size_in_kb}K"; then
>  			panic "reencryption of filesystem $1 cannot continue!"
>  		fi
> +
> +		if [ "$FAST_REENCRYPTION" = "1" ]; then
> +			# use temporarily loop device to simulate shrinked device
> +			# because cryptsetup uses device size at reducing
> +			"$LOSETUP_PATH" --sizelimit "${reduced_size_in_kb}K" "$loop_device" "$1"
> +		fi
>  		;;
>  	squashfs|swap|"")
>  		[ "$debug" = "y" ] && echo "skip disk resize as it is not supported or unnecessary for fstype: '$partition_fstype'"
> @@ -96,9 +121,14 @@ EOF
>  		;;
>  	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 --reduce-device-size "$reduce_device_size"k "$reencrypt_device" < "$2"
>  	else
> -		/usr/sbin/cryptsetup reencrypt --encrypt --reduce-device-size "$reduce_device_size"k "$1" < "$2"
> +		/usr/sbin/cryptsetup reencrypt --encrypt --reduce-device-size "$reduce_device_size"k "$reencrypt_device" < "$2"
> +	fi
> +
> +	if [ "$FAST_REENCRYPTION" = "1" ]; then
> +		# remove temporarily loop device
> +		"$LOSETUP_PATH" -d "$loop_device"
>  	fi
>  }
>  for candidate in /dev/tpm*; do
> @@ -182,6 +212,12 @@ for partition_set in $partition_sets; do
>  			reencrypt_existing_partition "$part_device" "$tmp_key"
>  			enroll_tpm2_token "$part_device" "$tmp_key" "$tpm_device" "$tpm_key_algorithm" "$pcr_bank_hash_type"
>  			open_tpm2_partition "$part_device" "$crypt_mount_name" "$tpm_device"
> +			if [ "$FAST_REENCRYPTION" = "1" ]; then
> +				# expand encrypted partition to maximum
> +				/usr/sbin/cryptsetup resize "$decrypted_part"
> +				# expand filesystem within encrypted layer to maximum
> +				resize2fs "$decrypted_part" "${encrypted_size_in_kb}K"
> +			fi
>  			log_end_msg
>  		;;
>  		"format")
> diff --git a/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.2.bb b/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.2.bb
> index 1679133..76ce72c 100644
> --- a/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.2.bb
> +++ b/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.2.bb
> @@ -59,6 +59,10 @@ CRYPT_PARTITIONS ??= "home:/home:reencrypt var:/var:reencrypt"
>  CRYPT_CREATE_FILE_SYSTEM_CMD ??= "/usr/sbin/mke2fs -t ext4"
>  # Path to full (non-busybox) losetup binary
>  CRYPT_LOSETUP_PATH ??= "/usr/local/sbin/losetup"
> +# Fast reencryption state
> +# It uses temporary partition resize,
> +# consider security and data reliablity aspects when enabling
> +CRYPT_FAST_REENCRYPTION ??= "0"
>  # Timeout for creating / re-encrypting partitions on first boot
>  CRYPT_SETUP_TIMEOUT ??= "600"
>  # Watchdog to service during the initial setup of the crypto partitions
> @@ -70,7 +74,7 @@ CRYPT_ENCRYPTION_OPTIONAL ??= "false"
>  
>  TEMPLATE_VARS = "CRYPT_PARTITIONS CRYPT_CREATE_FILE_SYSTEM_CMD \
>      CRYPT_SETUP_TIMEOUT INITRAMFS_WATCHDOG_DEVICE CRYPT_HASH_TYPE \
> -    CRYPT_LOSETUP_PATH \
> +    CRYPT_LOSETUP_PATH CRYPT_FAST_REENCRYPTION \
>      CRYPT_KEY_ALGORITHM CRYPT_ENCRYPTION_OPTIONAL"
>  TEMPLATE_FILES = "encrypt_partition.env.tmpl"
>
Quirin Gylstorff July 12, 2024, 9:46 a.m. UTC | #2
On 7/12/24 11:30 AM, Jan Kiszka wrote:
> On 12.07.24 10:11, Stefan Koch wrote:
>> - When "CRYPT_FAST_REENCRYPTION" is set to "1" (consider security and
>>    data reliablity aspects when enabling):
> 
> Where are they documented?
> 
>>    - shrink partition temporarily to minimum
>>    - encrypt shrinked partition
>>    - expand encrypted partition to maximum
> 
> Can't we rather generate a layout that starts small and expands after
> encryption?
> 
> Jan
> 
>>
>> Signed-off-by: Stefan Koch <stefan-koch@siemens.com>
>> ---
>>   .../files/encrypt_partition.env.tmpl          |  1 +
>>   .../files/encrypt_partition.script            | 50 ++++++++++++++++---
>>   .../initramfs-crypt-hook_0.2.bb               |  6 ++-
>>   3 files changed, 49 insertions(+), 8 deletions(-)
>>
>> diff --git a/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.env.tmpl b/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.env.tmpl
>> index 72033d1..9f3df4f 100644
>> --- a/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.env.tmpl
>> +++ b/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.env.tmpl
>> @@ -6,3 +6,4 @@ HASH_TYPE="${CRYPT_HASH_TYPE}"
>>   KEY_ALGORITHM="${CRYPT_KEY_ALGORITHM}"
>>   ENCRYPTION_IS_OPTIONAL="${CRYPT_ENCRYPTION_OPTIONAL}"
>>   LOSETUP_PATH="${CRYPT_LOSETUP_PATH}"
>> +FAST_REENCRYPTION="${CRYPT_FAST_REENCRYPTION}"
>> diff --git a/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.script b/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.script
>> index f943aea..e768b54 100644
>> --- a/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.script
>> +++ b/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.script
>> @@ -62,13 +62,16 @@ service_watchdog() {
>>   }
>>   
>>   reencrypt_existing_partition() {
>> +	reencrypt_device="$1"
>>   	part_size_blocks="$(cat /sys/class/block/"$(awk -v dev="$1" 'BEGIN{split(dev,a,"/"); print a[3]}' )"/size)"
>> -	# reduce the filesystem and partition by 32M to fit the LUKS header
>> +	part_size_in_kb="$(expr "$part_size_blocks" / 2)" # blocksize 512 byte
>> +
>>   	partition_fstype=$(get_fstype "${1}")
>> +	# reduce the filesystem and partition by 32M to fit the LUKS header
>>   	reduce_device_size=32768
>> -	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"
>> +	reduce_device_size_blocks="$(expr "$reduce_device_size" \* 2)" # 512 byte blocks
>> +	reduced_size="$(expr "$part_size_blocks" - "$reduce_device_size_blocks" )"
>> +	reduced_size_in_kb="$(expr "$reduced_size" / 2)" # blocksize 512 byte
>>   	case $partition_fstype in
>>   	ext*)
>>   		# reduce the filesystem and partition by 32M to fit the LUKS header
>> @@ -84,9 +87,31 @@ EOF
>>   		if ! cryptsetup luksUUID "$1" &> /dev/null; then
>>   			e2fsck -p -f "$1"
>>   		fi
>> -		if ! resize2fs "$1" "${reduced_size_in_kb}"; then
>> +		# shrink partition temporarily to minimum
>> +		min_size_fsblocks="$(resize2fs "$1" -P | awk -F ": " '{ print $2 }')"
>> +		if [ "$FAST_REENCRYPTION" = "1" ] && loop_device="$("$LOSETUP_PATH" -f)" && [ -n "$min_size_fsblocks" ]; then
>> +			# set encrypted size for expanding step
>> +			encrypted_size_in_kb="$reduced_size_in_kb"
>> +			# minimum partition size
>> +			min_size_in_kb="$(expr "$min_size_fsblocks" \* 4)" # blocksize 4096 byte
>> +			# shrinked partition size (reduce_size + minimum partition size)
>> +			reduced_size_in_kb="$(expr "$reduce_device_size" + "$min_size_in_kb")"
>> +			# set loop device as reencrypt device
>> +			reencrypt_device="$loop_device"
>> +		else
>> +			# continue with default reencryption in failure case
>> +			FAST_REENCRYPTION="0"
>> +		fi
>> +
>> +		if ! resize2fs "$1" "${reduced_size_in_kb}K"; then
>>   			panic "reencryption of filesystem $1 cannot continue!"
>>   		fi
>> +
>> +		if [ "$FAST_REENCRYPTION" = "1" ]; then
>> +			# use temporarily loop device to simulate shrinked device
>> +			# because cryptsetup uses device size at reducing
>> +			"$LOSETUP_PATH" --sizelimit "${reduced_size_in_kb}K" "$loop_device" "$1"
>> +		fi
Why is this setup in a seperate if clause?
>>   		;;
>>   	squashfs|swap|"")
>>   		[ "$debug" = "y" ] && echo "skip disk resize as it is not supported or unnecessary for fstype: '$partition_fstype'"
>> @@ -96,9 +121,14 @@ EOF
>>   		;;
>>   	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 --reduce-device-size "$reduce_device_size"k "$reencrypt_device" < "$2"
>>   	else
>> -		/usr/sbin/cryptsetup reencrypt --encrypt --reduce-device-size "$reduce_device_size"k "$1" < "$2"
>> +		/usr/sbin/cryptsetup reencrypt --encrypt --reduce-device-size "$reduce_device_size"k "$reencrypt_device" < "$2"
>> +	fi
>> +
>> +	if [ "$FAST_REENCRYPTION" = "1" ]; then
>> +		# remove temporarily loop device
>> +		"$LOSETUP_PATH" -d "$loop_device"
>>   	fi
>>   }
>>   for candidate in /dev/tpm*; do
>> @@ -182,6 +212,12 @@ for partition_set in $partition_sets; do
>>   			reencrypt_existing_partition "$part_device" "$tmp_key"
>>   			enroll_tpm2_token "$part_device" "$tmp_key" "$tpm_device" "$tpm_key_algorithm" "$pcr_bank_hash_type"
>>   			open_tpm2_partition "$part_device" "$crypt_mount_name" "$tpm_device"
>> +			if [ "$FAST_REENCRYPTION" = "1" ]; then
>> +				# expand encrypted partition to maximum
>> +				/usr/sbin/cryptsetup resize "$decrypted_part"
>> +				# expand filesystem within encrypted layer to maximum
>> +				resize2fs "$decrypted_part" "${encrypted_size_in_kb}K"
>> +			fi
>>   			log_end_msg
>>   		;;
>>   		"format")
>> diff --git a/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.2.bb b/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.2.bb
>> index 1679133..76ce72c 100644
>> --- a/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.2.bb
>> +++ b/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.2.bb
>> @@ -59,6 +59,10 @@ CRYPT_PARTITIONS ??= "home:/home:reencrypt var:/var:reencrypt"
>>   CRYPT_CREATE_FILE_SYSTEM_CMD ??= "/usr/sbin/mke2fs -t ext4"
>>   # Path to full (non-busybox) losetup binary
>>   CRYPT_LOSETUP_PATH ??= "/usr/local/sbin/losetup"
Is this variable necessary? I would expect that if the real tool is 
available the busybox variant is not used.

Quirin
>> +# Fast reencryption state
>> +# It uses temporary partition resize,
>> +# consider security and data reliablity aspects when enabling
>> +CRYPT_FAST_REENCRYPTION ??= "0"
>>   # Timeout for creating / re-encrypting partitions on first boot
>>   CRYPT_SETUP_TIMEOUT ??= "600"
>>   # Watchdog to service during the initial setup of the crypto partitions
>> @@ -70,7 +74,7 @@ CRYPT_ENCRYPTION_OPTIONAL ??= "false"
>>   
>>   TEMPLATE_VARS = "CRYPT_PARTITIONS CRYPT_CREATE_FILE_SYSTEM_CMD \
>>       CRYPT_SETUP_TIMEOUT INITRAMFS_WATCHDOG_DEVICE CRYPT_HASH_TYPE \
>> -    CRYPT_LOSETUP_PATH \
>> +    CRYPT_LOSETUP_PATH CRYPT_FAST_REENCRYPTION \
>>       CRYPT_KEY_ALGORITHM CRYPT_ENCRYPTION_OPTIONAL"
>>   TEMPLATE_FILES = "encrypt_partition.env.tmpl"
>>   
>
Stefan Koch July 12, 2024, 9:51 a.m. UTC | #3
On Fri, 2024-07-12 at 11:30 +0200, Jan Kiszka wrote:
> On 12.07.24 10:11, Stefan Koch wrote:
> > - When "CRYPT_FAST_REENCRYPTION" is set to "1" (consider security
> > and
> >   data reliablity aspects when enabling):
> 
> Where are they documented?
It's meant to make a project specific self-consideration.
The only thing to know is, that not every block is handled by the disk
encryption. As example, the Debian installer overwrites the whole
partition for random data, what is done by the non-fast reencryption
*implicit* because of handling of every block.
But anyway the format mechanism does not make this security
consideration, might be relevant when running on a device that is
already at customer side.

Two things for consideration:
- keep in mind that non-encrypted blocks may remain (former existing
data)
- even without data, clusters that *will* contain encrypted data are
not hidden, so the filesize could be not hidden
- and more topics to find out when doing a security consideration
> 
> >   - shrink partition temporarily to minimum
> >   - encrypt shrinked partition
> >   - expand encrypted partition to maximum
> 
> Can't we rather generate a layout that starts small and expands after
> encryption?
When using it on devices that are still at customer side, shrinking is
needed, too.
But keep in mind, that a power loss at reencryption will destroy all
data. Because the key is stored within the TPM *after* reencryption has
succeed. Cryptsetup is capable of resuming a partial reencryption, but
only with a key (and not one from TPM, might be in future with the
Debian 13 version of cryptsetup).
> 
> Jan
> 
> > 
> > Signed-off-by: Stefan Koch <stefan-koch@siemens.com>
> > ---
> >  .../files/encrypt_partition.env.tmpl          |  1 +
> >  .../files/encrypt_partition.script            | 50
> > ++++++++++++++++---
> >  .../initramfs-crypt-hook_0.2.bb               |  6 ++-
> >  3 files changed, 49 insertions(+), 8 deletions(-)
> > 
> > diff --git a/recipes-initramfs/initramfs-crypt-
> > hook/files/encrypt_partition.env.tmpl b/recipes-
> > initramfs/initramfs-crypt-hook/files/encrypt_partition.env.tmpl
> > index 72033d1..9f3df4f 100644
> > --- a/recipes-initramfs/initramfs-crypt-
> > hook/files/encrypt_partition.env.tmpl
> > +++ b/recipes-initramfs/initramfs-crypt-
> > hook/files/encrypt_partition.env.tmpl
> > @@ -6,3 +6,4 @@ HASH_TYPE="${CRYPT_HASH_TYPE}"
> >  KEY_ALGORITHM="${CRYPT_KEY_ALGORITHM}"
> >  ENCRYPTION_IS_OPTIONAL="${CRYPT_ENCRYPTION_OPTIONAL}"
> >  LOSETUP_PATH="${CRYPT_LOSETUP_PATH}"
> > +FAST_REENCRYPTION="${CRYPT_FAST_REENCRYPTION}"
> > diff --git a/recipes-initramfs/initramfs-crypt-
> > hook/files/encrypt_partition.script b/recipes-initramfs/initramfs-
> > crypt-hook/files/encrypt_partition.script
> > index f943aea..e768b54 100644
> > --- a/recipes-initramfs/initramfs-crypt-
> > hook/files/encrypt_partition.script
> > +++ b/recipes-initramfs/initramfs-crypt-
> > hook/files/encrypt_partition.script
> > @@ -62,13 +62,16 @@ service_watchdog() {
> >  }
> >  
> >  reencrypt_existing_partition() {
> > +       reencrypt_device="$1"
> >         part_size_blocks="$(cat /sys/class/block/"$(awk -v dev="$1"
> > 'BEGIN{split(dev,a,"/"); print a[3]}' )"/size)"
> > -       # reduce the filesystem and partition by 32M to fit the
> > LUKS header
> > +       part_size_in_kb="$(expr "$part_size_blocks" / 2)" #
> > blocksize 512 byte
> > +
> >         partition_fstype=$(get_fstype "${1}")
> > +       # reduce the filesystem and partition by 32M to fit the
> > LUKS header
> >         reduce_device_size=32768
> > -       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"
> > +       reduce_device_size_blocks="$(expr "$reduce_device_size" \*
> > 2)" # 512 byte blocks
> > +       reduced_size="$(expr "$part_size_blocks" -
> > "$reduce_device_size_blocks" )"
> > +       reduced_size_in_kb="$(expr "$reduced_size" / 2)" #
> > blocksize 512 byte
> >         case $partition_fstype in
> >         ext*)
> >                 # reduce the filesystem and partition by 32M to fit
> > the LUKS header
> > @@ -84,9 +87,31 @@ EOF
> >                 if ! cryptsetup luksUUID "$1" &> /dev/null; then
> >                         e2fsck -p -f "$1"
> >                 fi
> > -               if ! resize2fs "$1" "${reduced_size_in_kb}"; then
> > +               # shrink partition temporarily to minimum
> > +               min_size_fsblocks="$(resize2fs "$1" -P | awk -F ":
> > " '{ print $2 }')"
> > +               if [ "$FAST_REENCRYPTION" = "1" ] &&
> > loop_device="$("$LOSETUP_PATH" -f)" && [ -n "$min_size_fsblocks" ];
> > then
> > +                       # set encrypted size for expanding step
> > +                       encrypted_size_in_kb="$reduced_size_in_kb"
> > +                       # minimum partition size
> > +                       min_size_in_kb="$(expr "$min_size_fsblocks"
> > \* 4)" # blocksize 4096 byte
> > +                       # shrinked partition size (reduce_size +
> > minimum partition size)
> > +                       reduced_size_in_kb="$(expr
> > "$reduce_device_size" + "$min_size_in_kb")"
> > +                       # set loop device as reencrypt device
> > +                       reencrypt_device="$loop_device"
> > +               else
> > +                       # continue with default reencryption in
> > failure case
> > +                       FAST_REENCRYPTION="0"
> > +               fi
> > +
> > +               if ! resize2fs "$1" "${reduced_size_in_kb}K"; then
> >                         panic "reencryption of filesystem $1 cannot
> > continue!"
> >                 fi
> > +
> > +               if [ "$FAST_REENCRYPTION" = "1" ]; then
> > +                       # use temporarily loop device to simulate
> > shrinked device
> > +                       # because cryptsetup uses device size at
> > reducing
> > +                       "$LOSETUP_PATH" --sizelimit
> > "${reduced_size_in_kb}K" "$loop_device" "$1"
> > +               fi
> >                 ;;
> >         squashfs|swap|"")
> >                 [ "$debug" = "y" ] && echo "skip disk resize as it
> > is not supported or unnecessary for fstype: '$partition_fstype'"
> > @@ -96,9 +121,14 @@ EOF
> >                 ;;
> >         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 --reduce-
> > device-size "$reduce_device_size"k "$reencrypt_device" < "$2"
> >         else
> > -               /usr/sbin/cryptsetup reencrypt --encrypt --reduce-
> > device-size "$reduce_device_size"k "$1" < "$2"
> > +               /usr/sbin/cryptsetup reencrypt --encrypt --reduce-
> > device-size "$reduce_device_size"k "$reencrypt_device" < "$2"
> > +       fi
> > +
> > +       if [ "$FAST_REENCRYPTION" = "1" ]; then
> > +               # remove temporarily loop device
> > +               "$LOSETUP_PATH" -d "$loop_device"
> >         fi
> >  }
> >  for candidate in /dev/tpm*; do
> > @@ -182,6 +212,12 @@ for partition_set in $partition_sets; do
> >                         reencrypt_existing_partition "$part_device"
> > "$tmp_key"
> >                         enroll_tpm2_token "$part_device" "$tmp_key"
> > "$tpm_device" "$tpm_key_algorithm" "$pcr_bank_hash_type"
> >                         open_tpm2_partition "$part_device"
> > "$crypt_mount_name" "$tpm_device"
> > +                       if [ "$FAST_REENCRYPTION" = "1" ]; then
> > +                               # expand encrypted partition to
> > maximum
> > +                               /usr/sbin/cryptsetup resize
> > "$decrypted_part"
> > +                               # expand filesystem within
> > encrypted layer to maximum
> > +                               resize2fs "$decrypted_part"
> > "${encrypted_size_in_kb}K"
> > +                       fi
> >                         log_end_msg
> >                 ;;
> >                 "format")
> > diff --git a/recipes-initramfs/initramfs-crypt-hook/initramfs-
> > crypt-hook_0.2.bb b/recipes-initramfs/initramfs-crypt-
> > hook/initramfs-crypt-hook_0.2.bb
> > index 1679133..76ce72c 100644
> > --- a/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-
> > hook_0.2.bb
> > +++ b/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-
> > hook_0.2.bb
> > @@ -59,6 +59,10 @@ CRYPT_PARTITIONS ??= "home:/home:reencrypt
> > var:/var:reencrypt"
> >  CRYPT_CREATE_FILE_SYSTEM_CMD ??= "/usr/sbin/mke2fs -t ext4"
> >  # Path to full (non-busybox) losetup binary
> >  CRYPT_LOSETUP_PATH ??= "/usr/local/sbin/losetup"
> > +# Fast reencryption state
> > +# It uses temporary partition resize,
> > +# consider security and data reliablity aspects when enabling
> > +CRYPT_FAST_REENCRYPTION ??= "0"
> >  # Timeout for creating / re-encrypting partitions on first boot
> >  CRYPT_SETUP_TIMEOUT ??= "600"
> >  # Watchdog to service during the initial setup of the crypto
> > partitions
> > @@ -70,7 +74,7 @@ CRYPT_ENCRYPTION_OPTIONAL ??= "false"
> >  
> >  TEMPLATE_VARS = "CRYPT_PARTITIONS CRYPT_CREATE_FILE_SYSTEM_CMD \
> >      CRYPT_SETUP_TIMEOUT INITRAMFS_WATCHDOG_DEVICE CRYPT_HASH_TYPE
> > \
> > -    CRYPT_LOSETUP_PATH \
> > +    CRYPT_LOSETUP_PATH CRYPT_FAST_REENCRYPTION \
> >      CRYPT_KEY_ALGORITHM CRYPT_ENCRYPTION_OPTIONAL"
> >  TEMPLATE_FILES = "encrypt_partition.env.tmpl"
> >  
>
Stefan Koch July 12, 2024, 10 a.m. UTC | #4
On Fri, 2024-07-12 at 11:46 +0200, Gylstorff Quirin wrote:
> 
> 
> On 7/12/24 11:30 AM, Jan Kiszka wrote:
> > On 12.07.24 10:11, Stefan Koch wrote:
> > > - When "CRYPT_FAST_REENCRYPTION" is set to "1" (consider security
> > > and
> > >    data reliablity aspects when enabling):
> > 
> > Where are they documented?
> > 
> > >    - shrink partition temporarily to minimum
> > >    - encrypt shrinked partition
> > >    - expand encrypted partition to maximum
> > 
> > Can't we rather generate a layout that starts small and expands
> > after
> > encryption?
> > 
> > Jan
> > 
> > > 
> > > Signed-off-by: Stefan Koch <stefan-koch@siemens.com>
> > > ---
> > >   .../files/encrypt_partition.env.tmpl          |  1 +
> > >   .../files/encrypt_partition.script            | 50
> > > ++++++++++++++++---
> > >   .../initramfs-crypt-hook_0.2.bb               |  6 ++-
> > >   3 files changed, 49 insertions(+), 8 deletions(-)
> > > 
> > > diff --git a/recipes-initramfs/initramfs-crypt-
> > > hook/files/encrypt_partition.env.tmpl b/recipes-
> > > initramfs/initramfs-crypt-hook/files/encrypt_partition.env.tmpl
> > > index 72033d1..9f3df4f 100644
> > > --- a/recipes-initramfs/initramfs-crypt-
> > > hook/files/encrypt_partition.env.tmpl
> > > +++ b/recipes-initramfs/initramfs-crypt-
> > > hook/files/encrypt_partition.env.tmpl
> > > @@ -6,3 +6,4 @@ HASH_TYPE="${CRYPT_HASH_TYPE}"
> > >   KEY_ALGORITHM="${CRYPT_KEY_ALGORITHM}"
> > >   ENCRYPTION_IS_OPTIONAL="${CRYPT_ENCRYPTION_OPTIONAL}"
> > >   LOSETUP_PATH="${CRYPT_LOSETUP_PATH}"
> > > +FAST_REENCRYPTION="${CRYPT_FAST_REENCRYPTION}"
> > > diff --git a/recipes-initramfs/initramfs-crypt-
> > > hook/files/encrypt_partition.script b/recipes-
> > > initramfs/initramfs-crypt-hook/files/encrypt_partition.script
> > > index f943aea..e768b54 100644
> > > --- a/recipes-initramfs/initramfs-crypt-
> > > hook/files/encrypt_partition.script
> > > +++ b/recipes-initramfs/initramfs-crypt-
> > > hook/files/encrypt_partition.script
> > > @@ -62,13 +62,16 @@ service_watchdog() {
> > >   }
> > >   
> > >   reencrypt_existing_partition() {
> > > +       reencrypt_device="$1"
> > >         part_size_blocks="$(cat /sys/class/block/"$(awk -v
> > > dev="$1" 'BEGIN{split(dev,a,"/"); print a[3]}' )"/size)"
> > > -       # reduce the filesystem and partition by 32M to fit the
> > > LUKS header
> > > +       part_size_in_kb="$(expr "$part_size_blocks" / 2)" #
> > > blocksize 512 byte
> > > +
> > >         partition_fstype=$(get_fstype "${1}")
> > > +       # reduce the filesystem and partition by 32M to fit the
> > > LUKS header
> > >         reduce_device_size=32768
> > > -       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"
> > > +       reduce_device_size_blocks="$(expr "$reduce_device_size"
> > > \* 2)" # 512 byte blocks
> > > +       reduced_size="$(expr "$part_size_blocks" -
> > > "$reduce_device_size_blocks" )"
> > > +       reduced_size_in_kb="$(expr "$reduced_size" / 2)" #
> > > blocksize 512 byte
> > >         case $partition_fstype in
> > >         ext*)
> > >                 # reduce the filesystem and partition by 32M to
> > > fit the LUKS header
> > > @@ -84,9 +87,31 @@ EOF
> > >                 if ! cryptsetup luksUUID "$1" &> /dev/null; then
> > >                         e2fsck -p -f "$1"
> > >                 fi
> > > -               if ! resize2fs "$1" "${reduced_size_in_kb}"; then
> > > +               # shrink partition temporarily to minimum
> > > +               min_size_fsblocks="$(resize2fs "$1" -P | awk -F
> > > ": " '{ print $2 }')"
> > > +               if [ "$FAST_REENCRYPTION" = "1" ] &&
> > > loop_device="$("$LOSETUP_PATH" -f)" && [ -n "$min_size_fsblocks"
> > > ]; then
> > > +                       # set encrypted size for expanding step
> > > +                       encrypted_size_in_kb="$reduced_size_in_kb
> > > "
> > > +                       # minimum partition size
> > > +                       min_size_in_kb="$(expr
> > > "$min_size_fsblocks" \* 4)" # blocksize 4096 byte
> > > +                       # shrinked partition size (reduce_size +
> > > minimum partition size)
> > > +                       reduced_size_in_kb="$(expr
> > > "$reduce_device_size" + "$min_size_in_kb")"
> > > +                       # set loop device as reencrypt device
> > > +                       reencrypt_device="$loop_device"
> > > +               else
> > > +                       # continue with default reencryption in
> > > failure case
> > > +                       FAST_REENCRYPTION="0"
> > > +               fi
> > > +
> > > +               if ! resize2fs "$1" "${reduced_size_in_kb}K";
> > > then
> > >                         panic "reencryption of filesystem $1
> > > cannot continue!"
> > >                 fi
> > > +
> > > +               if [ "$FAST_REENCRYPTION" = "1" ]; then
> > > +                       # use temporarily loop device to simulate
> > > shrinked device
> > > +                       # because cryptsetup uses device size at
> > > reducing
> > > +                       "$LOSETUP_PATH" --sizelimit
> > > "${reduced_size_in_kb}K" "$loop_device" "$1"
> > > +               fi
> Why is this setup in a seperate if clause?
> > >                 ;;
> > >         squashfs|swap|"")
> > >                 [ "$debug" = "y" ] && echo "skip disk resize as
> > > it is not supported or unnecessary for fstype:
> > > '$partition_fstype'"
> > > @@ -96,9 +121,14 @@ EOF
> > >                 ;;
> > >         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 --reduce-
> > > device-size "$reduce_device_size"k "$reencrypt_device" < "$2"
> > >         else
> > > -               /usr/sbin/cryptsetup reencrypt --encrypt --
> > > reduce-device-size "$reduce_device_size"k "$1" < "$2"
> > > +               /usr/sbin/cryptsetup reencrypt --encrypt --
> > > reduce-device-size "$reduce_device_size"k "$reencrypt_device" <
> > > "$2"
> > > +       fi
> > > +
> > > +       if [ "$FAST_REENCRYPTION" = "1" ]; then
> > > +               # remove temporarily loop device
> > > +               "$LOSETUP_PATH" -d "$loop_device"
> > >         fi
> > >   }
> > >   for candidate in /dev/tpm*; do
> > > @@ -182,6 +212,12 @@ for partition_set in $partition_sets; do
> > >                         reencrypt_existing_partition
> > > "$part_device" "$tmp_key"
> > >                         enroll_tpm2_token "$part_device"
> > > "$tmp_key" "$tpm_device" "$tpm_key_algorithm"
> > > "$pcr_bank_hash_type"
> > >                         open_tpm2_partition "$part_device"
> > > "$crypt_mount_name" "$tpm_device"
> > > +                       if [ "$FAST_REENCRYPTION" = "1" ]; then
> > > +                               # expand encrypted partition to
> > > maximum
> > > +                               /usr/sbin/cryptsetup resize
> > > "$decrypted_part"
> > > +                               # expand filesystem within
> > > encrypted layer to maximum
> > > +                               resize2fs "$decrypted_part"
> > > "${encrypted_size_in_kb}K"
> > > +                       fi
> > >                         log_end_msg
> > >                 ;;
> > >                 "format")
> > > diff --git a/recipes-initramfs/initramfs-crypt-hook/initramfs-
> > > crypt-hook_0.2.bb b/recipes-initramfs/initramfs-crypt-
> > > hook/initramfs-crypt-hook_0.2.bb
> > > index 1679133..76ce72c 100644
> > > --- a/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-
> > > hook_0.2.bb
> > > +++ b/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-
> > > hook_0.2.bb
> > > @@ -59,6 +59,10 @@ CRYPT_PARTITIONS ??= "home:/home:reencrypt
> > > var:/var:reencrypt"
> > >   CRYPT_CREATE_FILE_SYSTEM_CMD ??= "/usr/sbin/mke2fs -t ext4"
> > >   # Path to full (non-busybox) losetup binary
> > >   CRYPT_LOSETUP_PATH ??= "/usr/local/sbin/losetup"
> Is this variable necessary? I would expect that if the real tool is 
> available the busybox variant is not used.
It's a bit like 67d2737762fe6e2036962debc9381267e16012c0 "Avoid calling
of tiny mke2fs from busybox".
Could be the case that this might be only relevant for a initramfs that
is containing a busybox because of other reasons.
> 
> Quirin
> > > +# Fast reencryption state
> > > +# It uses temporary partition resize,
> > > +# consider security and data reliablity aspects when enabling
> > > +CRYPT_FAST_REENCRYPTION ??= "0"
> > >   # Timeout for creating / re-encrypting partitions on first boot
> > >   CRYPT_SETUP_TIMEOUT ??= "600"
> > >   # Watchdog to service during the initial setup of the crypto
> > > partitions
> > > @@ -70,7 +74,7 @@ CRYPT_ENCRYPTION_OPTIONAL ??= "false"
> > >   
> > >   TEMPLATE_VARS = "CRYPT_PARTITIONS CRYPT_CREATE_FILE_SYSTEM_CMD
> > > \
> > >       CRYPT_SETUP_TIMEOUT INITRAMFS_WATCHDOG_DEVICE
> > > CRYPT_HASH_TYPE \
> > > -    CRYPT_LOSETUP_PATH \
> > > +    CRYPT_LOSETUP_PATH CRYPT_FAST_REENCRYPTION \
> > >       CRYPT_KEY_ALGORITHM CRYPT_ENCRYPTION_OPTIONAL"
> > >   TEMPLATE_FILES = "encrypt_partition.env.tmpl"
> > >   
> >
diff mbox series

Patch

diff --git a/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.env.tmpl b/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.env.tmpl
index 72033d1..9f3df4f 100644
--- a/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.env.tmpl
+++ b/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.env.tmpl
@@ -6,3 +6,4 @@  HASH_TYPE="${CRYPT_HASH_TYPE}"
 KEY_ALGORITHM="${CRYPT_KEY_ALGORITHM}"
 ENCRYPTION_IS_OPTIONAL="${CRYPT_ENCRYPTION_OPTIONAL}"
 LOSETUP_PATH="${CRYPT_LOSETUP_PATH}"
+FAST_REENCRYPTION="${CRYPT_FAST_REENCRYPTION}"
diff --git a/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.script b/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.script
index f943aea..e768b54 100644
--- a/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.script
+++ b/recipes-initramfs/initramfs-crypt-hook/files/encrypt_partition.script
@@ -62,13 +62,16 @@  service_watchdog() {
 }
 
 reencrypt_existing_partition() {
+	reencrypt_device="$1"
 	part_size_blocks="$(cat /sys/class/block/"$(awk -v dev="$1" 'BEGIN{split(dev,a,"/"); print a[3]}' )"/size)"
-	# reduce the filesystem and partition by 32M to fit the LUKS header
+	part_size_in_kb="$(expr "$part_size_blocks" / 2)" # blocksize 512 byte
+
 	partition_fstype=$(get_fstype "${1}")
+	# reduce the filesystem and partition by 32M to fit the LUKS header
 	reduce_device_size=32768
-	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"
+	reduce_device_size_blocks="$(expr "$reduce_device_size" \* 2)" # 512 byte blocks
+	reduced_size="$(expr "$part_size_blocks" - "$reduce_device_size_blocks" )"
+	reduced_size_in_kb="$(expr "$reduced_size" / 2)" # blocksize 512 byte
 	case $partition_fstype in
 	ext*)
 		# reduce the filesystem and partition by 32M to fit the LUKS header
@@ -84,9 +87,31 @@  EOF
 		if ! cryptsetup luksUUID "$1" &> /dev/null; then
 			e2fsck -p -f "$1"
 		fi
-		if ! resize2fs "$1" "${reduced_size_in_kb}"; then
+		# shrink partition temporarily to minimum
+		min_size_fsblocks="$(resize2fs "$1" -P | awk -F ": " '{ print $2 }')"
+		if [ "$FAST_REENCRYPTION" = "1" ] && loop_device="$("$LOSETUP_PATH" -f)" && [ -n "$min_size_fsblocks" ]; then
+			# set encrypted size for expanding step
+			encrypted_size_in_kb="$reduced_size_in_kb"
+			# minimum partition size
+			min_size_in_kb="$(expr "$min_size_fsblocks" \* 4)" # blocksize 4096 byte
+			# shrinked partition size (reduce_size + minimum partition size)
+			reduced_size_in_kb="$(expr "$reduce_device_size" + "$min_size_in_kb")"
+			# set loop device as reencrypt device
+			reencrypt_device="$loop_device"
+		else
+			# continue with default reencryption in failure case
+			FAST_REENCRYPTION="0"
+		fi
+
+		if ! resize2fs "$1" "${reduced_size_in_kb}K"; then
 			panic "reencryption of filesystem $1 cannot continue!"
 		fi
+
+		if [ "$FAST_REENCRYPTION" = "1" ]; then
+			# use temporarily loop device to simulate shrinked device
+			# because cryptsetup uses device size at reducing
+			"$LOSETUP_PATH" --sizelimit "${reduced_size_in_kb}K" "$loop_device" "$1"
+		fi
 		;;
 	squashfs|swap|"")
 		[ "$debug" = "y" ] && echo "skip disk resize as it is not supported or unnecessary for fstype: '$partition_fstype'"
@@ -96,9 +121,14 @@  EOF
 		;;
 	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 --reduce-device-size "$reduce_device_size"k "$reencrypt_device" < "$2"
 	else
-		/usr/sbin/cryptsetup reencrypt --encrypt --reduce-device-size "$reduce_device_size"k "$1" < "$2"
+		/usr/sbin/cryptsetup reencrypt --encrypt --reduce-device-size "$reduce_device_size"k "$reencrypt_device" < "$2"
+	fi
+
+	if [ "$FAST_REENCRYPTION" = "1" ]; then
+		# remove temporarily loop device
+		"$LOSETUP_PATH" -d "$loop_device"
 	fi
 }
 for candidate in /dev/tpm*; do
@@ -182,6 +212,12 @@  for partition_set in $partition_sets; do
 			reencrypt_existing_partition "$part_device" "$tmp_key"
 			enroll_tpm2_token "$part_device" "$tmp_key" "$tpm_device" "$tpm_key_algorithm" "$pcr_bank_hash_type"
 			open_tpm2_partition "$part_device" "$crypt_mount_name" "$tpm_device"
+			if [ "$FAST_REENCRYPTION" = "1" ]; then
+				# expand encrypted partition to maximum
+				/usr/sbin/cryptsetup resize "$decrypted_part"
+				# expand filesystem within encrypted layer to maximum
+				resize2fs "$decrypted_part" "${encrypted_size_in_kb}K"
+			fi
 			log_end_msg
 		;;
 		"format")
diff --git a/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.2.bb b/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.2.bb
index 1679133..76ce72c 100644
--- a/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.2.bb
+++ b/recipes-initramfs/initramfs-crypt-hook/initramfs-crypt-hook_0.2.bb
@@ -59,6 +59,10 @@  CRYPT_PARTITIONS ??= "home:/home:reencrypt var:/var:reencrypt"
 CRYPT_CREATE_FILE_SYSTEM_CMD ??= "/usr/sbin/mke2fs -t ext4"
 # Path to full (non-busybox) losetup binary
 CRYPT_LOSETUP_PATH ??= "/usr/local/sbin/losetup"
+# Fast reencryption state
+# It uses temporary partition resize,
+# consider security and data reliablity aspects when enabling
+CRYPT_FAST_REENCRYPTION ??= "0"
 # Timeout for creating / re-encrypting partitions on first boot
 CRYPT_SETUP_TIMEOUT ??= "600"
 # Watchdog to service during the initial setup of the crypto partitions
@@ -70,7 +74,7 @@  CRYPT_ENCRYPTION_OPTIONAL ??= "false"
 
 TEMPLATE_VARS = "CRYPT_PARTITIONS CRYPT_CREATE_FILE_SYSTEM_CMD \
     CRYPT_SETUP_TIMEOUT INITRAMFS_WATCHDOG_DEVICE CRYPT_HASH_TYPE \
-    CRYPT_LOSETUP_PATH \
+    CRYPT_LOSETUP_PATH CRYPT_FAST_REENCRYPTION \
     CRYPT_KEY_ALGORITHM CRYPT_ENCRYPTION_OPTIONAL"
 TEMPLATE_FILES = "encrypt_partition.env.tmpl"