Allow --reduce-device-size and --device-size in encrypt action.

Fixes: #822
This commit is contained in:
Ondrej Kozina
2025-05-20 09:54:22 +02:00
parent ad30673dc5
commit 10ab6be262
6 changed files with 91 additions and 6 deletions

View File

@@ -124,6 +124,13 @@ ifdef::ACTION_REENCRYPT[]
It means that only specified area (from the start of the device
to the specified size) will be reencrypted.
+
*LUKS2*:
When used together with --reduce-device-size, only the initial _size_ value
(--device-size parameter) of data is shifted backwards while being encrypted.
+
*NOTE*:
The sum of --device-size and --reduce-device-size values must not exceed real device size.
+
*WARNING:* This is destructive operation. Data beyond --device-size limit may
be lost after operation gets finished.
endif::[]
@@ -993,11 +1000,18 @@ unrecoverable.
+
*LUKS2*:
Initialize LUKS2 reencryption with data device size reduction
(currently only encryption mode is supported).
(currently only encryption mode is supported). The last _size_ sectors
on the original plaintext device is used for temporarily storing original
first data segment. The former first data segment is replaced with LUKS2
header (half the _size_ value) and plaintext data are shifted backwards (
again half the _size_ value) while being encrypted.
+
Recommended minimal size is twice the default LUKS2 header size
(--reduce-device-size 32M) for encryption mode.
+
*NOTE*:
The sum of --device-size and --reduce-device-size values must not exceed real device size.
+
*LUKS1*:
Enlarge data offset to specified value by shrinking device size.
+

View File

@@ -142,6 +142,13 @@ is unused (e.g.: does not contain filesystem data):
*cryptsetup reencrypt --encrypt --type luks2 --reduce-device-size 32m /dev/plaintext_device*
Encrypt LUKS2 device (in-place). Only the initial 1 GiB of original
_/dev/plaintext_ data is encrypted while being shifted backwards.
Make sure last 32 MiB (tail) on the data device is unused (e.g.: does
not contain any data):
*cryptsetup reencrypt --encrypt --type luks2 --device-size 1g --reduce-device-size 32m /dev/plaintext_device*
Encrypt LUKS2 device (in-place) with detached header put in a file:
*cryptsetup reencrypt --encrypt --type luks2 --header my_luks2_header /dev/plaintext_device*

View File

@@ -3377,9 +3377,6 @@ static const char *verify_resize(void)
static const char *verify_reencrypt(void)
{
if (ARG_SET(OPT_REDUCE_DEVICE_SIZE_ID) && ARG_SET(OPT_DEVICE_SIZE_ID))
return _("Options --reduce-device-size and --device-size cannot be combined.");
if (isLUKS1(luksType(device_type)) && ARG_SET(OPT_ACTIVE_NAME_ID))
return _("Option --active-name can be set only for LUKS2 device.");

View File

@@ -680,13 +680,15 @@ static int encrypt_luks2_init(struct crypt_device **cd, const char *data_device,
}
}
/* The --reduce-device-size has to be at least twice the size of first moved segment (LUKS2
* data offset) */
if (!ARG_SET(OPT_HEADER_ID) && ARG_UINT64(OPT_OFFSET_ID) &&
data_shift && (ARG_UINT64(OPT_OFFSET_ID) > (uint64_t)(imaxabs(data_shift) / (2 * SECTOR_SIZE)))) {
log_err(_("Requested data offset must be less than or equal to half of --reduce-device-size parameter."));
return -EINVAL;
}
/* TODO: ask user to confirm. It's useless to do data device reduction and than use smaller value */
/* It's useless to do data device reduction and than use smaller value */
if (!ARG_SET(OPT_HEADER_ID) && ARG_UINT64(OPT_OFFSET_ID) &&
data_shift && (ARG_UINT64(OPT_OFFSET_ID) < (uint64_t)(imaxabs(data_shift) / (2 * SECTOR_SIZE)))) {
data_shift = -(ARG_UINT64(OPT_OFFSET_ID) * 2 * SECTOR_SIZE);

View File

@@ -285,7 +285,6 @@ exp_fail reencrypt DEV --reduce-device-size 2G # max 1g
exp_fail reencrypt DEV --reduce-device-size $((64*1024*1024+1))
exp_fail reencrypt DEV --reduce-device-size -64m
exp_pass reencrypt DEV --reduce-device-size 64m
exp_fail reencrypt DEV --reduce-device-size 64m --device-size 100g
# bugs
# exp_fail open DEV --decrypt --header H
# exp_fail open DEV --encrypt

View File

@@ -297,6 +297,28 @@ resize_file() # $1 dev, $2 shrink bytes
losetup -c $LOOPDEV
}
error_io() { # $1 dmdev, $2 data dev, $3 offset, $4 size
local _dev_size=$(blockdev --getsz /dev/mapper/$1)
local _offset=$(($3+$4))
local _size=$((_dev_size-_offset))
local _table=
dmsetup create $1-err --table "0 $_dev_size error" || fail
if [ $3 -ne 0 ]; then
_table="0 $3 linear $2 0\n"
fi
_table=$_table"$3 $4 error"
if [ $_size -ne 0 ]; then
_table="$_table\n$_offset $_size linear $2 $_offset"
fi
echo -e "$_table" | dmsetup load $1 || fail
dmsetup resume $1 || fail
blockdev --setra 0 /dev/mapper/$1
}
error_writes() { # $1 dmdev, $2 data dev, $3 offset, $4 size
local _dev_size=$(blockdev --getsz /dev/mapper/$1)
local _offset=$(($3+$4))
@@ -1206,6 +1228,50 @@ echo $PWD1 | $CRYPTSETUP reencrypt $DEV --encrypt --reduce-device-size 64M --ini
check_hash_dev_head /dev/mapper/$DEV_NAME 2048 $HASH2
echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q || fail
check_hash_dev_head /dev/mapper/$DEV_NAME 2048 $HASH2
$CRYPTSETUP close $DEV_NAME || fail
# encryption with both data shift and reduced data size
prepare_linear_dev 65
# --reduce-device-size + --device-size (1MiB+512B) is larger than real device size
echo $PWD1 | $CRYPTSETUP reencrypt $DEV --encrypt --init-only --device-size 2049s --reduce-device-size 64M -q $FAST_PBKDF_ARGON >/dev/null 2>&1 && fail
$CRYPTSETUP isLuks --type luks2 $DEV && fail
# no changes in data device
check_hash_dev_head $DEV 2048 $HASH2
# --reduce-device-size (1MiB+8KiB) + --device-size (64MiB - (8KiB-512B)) is larger than real device size
echo $PWD1 | $CRYPTSETUP reencrypt $DEV --encrypt --init-only --device-size 131057s --reduce-device-size 2064s -q $FAST_PBKDF_ARGON >/dev/null 2>&1 && fail
$CRYPTSETUP isLuks --type luks2 $DEV && fail
# no changes in data device
check_hash_dev_head $DEV 2048 $HASH2
echo $PWD1 | $CRYPTSETUP reencrypt $DEV --encrypt --device-size 1M --reduce-device-size 32M -q $FAST_PBKDF_ARGON || fail
check_hash_head $PWD1 2048 $HASH2
# test limit values (--device-size + --reduce-device-size = real device size)
wipe_dev_head $DEV 43
echo $PWD1 | $CRYPTSETUP reencrypt $DEV --encrypt --device-size 43M --reduce-device-size 22M -q $FAST_PBKDF_ARGON || fail
check_hash_head $PWD1 88064 $HASH6
wipe_dev_head $DEV 1
# check reencryption code does not touch data in-between --device-size and --reduce-device-size
# data device: [ reduce-device-size / 2 ] [ device-size ] [ error minefield ] [ reduce-device-size / 2]
ERROFFSET=34816
ERRLENGTH=65536
error_io $OVRDEV $OLD_DEV $ERROFFSET $ERRLENGTH
echo $PWD1 | $CRYPTSETUP reencrypt $DEV --encrypt --device-size 1M --reduce-device-size 32M -q $FAST_PBKDF_ARGON || fail
fix_writes $OVRDEV $OLD_DEV
check_hash_head $PWD1 2048 $HASH2
wipe_dev_head $DEV 43
ERROFFSET=104448
ERRLENGTH=12288
# data device: [ reduce-device-size / 2 ] [ device-size ] [ error minefield ] [ reduce-device-size / 2]
error_io $OVRDEV $OLD_DEV $ERROFFSET $ERRLENGTH
echo $PWD1 | $CRYPTSETUP reencrypt $DEV --encrypt --device-size 43M --reduce-device-size 16M -q $FAST_PBKDF_ARGON || fail
fix_writes $OVRDEV $OLD_DEV
check_hash_head $PWD1 88064 $HASH6
echo "[3] Encryption with detached header"
preparebig 256