Do not allow dangerous sector size change during reencryption.

By changing encryption sector size during reencryption we may
increase effective logical block size for dm-crypt active device.

For example if hosted filesystem on encrypted data device
has block size set to 512 bytes and we increase dm-crypt logical
size durign reencryption to 4096 bytes it breaks the filesystem.

Do not allow encryption sector size to be increased over value
provided by fs superblock in BLOCK_SIZE property.

The check is applied while initialising LUKS2 device encryption
(reencrypt --encrypt/--new) or when initialising LUKS2 reencryption
on active dm-crypt device.

Note that this check cannot be applied on offline device (data device
is encrypted).
This commit is contained in:
Ondrej Kozina
2022-04-13 12:33:43 +02:00
committed by Milan Broz
parent 38d1f01b12
commit c9da460b6c
4 changed files with 101 additions and 6 deletions

View File

@@ -302,6 +302,40 @@ static enum device_status_info check_luks_device(const char *device)
return dev_st; return dev_st;
} }
static int reencrypt_check_data_sb_block_size(const char *data_device, uint32_t new_sector_size)
{
int r;
char sb_name[32];
unsigned block_size;
assert(data_device);
r = tools_superblock_block_size(data_device, sb_name, sizeof(sb_name), &block_size);
if (r <= 0)
return r;
if (new_sector_size > block_size) {
log_err(_("Requested --sector-size %" PRIu32 " is incompatible with %s superblock\n"
"(block size: %" PRIu32 " bytes) detected on device %s."),
new_sector_size, sb_name, block_size, data_device);
return -EINVAL;
}
return 0;
}
static int reencrypt_check_active_device_sb_block_size(const char *active_device, uint32_t new_sector_size)
{
int r;
char dm_device[PATH_MAX];
r = snprintf(dm_device, sizeof(dm_device), "%s/%s", crypt_get_dir(), active_device);
if (r < 0 || (size_t)r >= sizeof(dm_device))
return -EINVAL;
return reencrypt_check_data_sb_block_size(dm_device, new_sector_size);
}
static int encrypt_luks2_init(struct crypt_device **cd, const char *data_device, const char *device_name) static int encrypt_luks2_init(struct crypt_device **cd, const char *data_device, const char *device_name)
{ {
int keyslot, r, fd; int keyslot, r, fd;
@@ -350,6 +384,12 @@ static int encrypt_luks2_init(struct crypt_device **cd, const char *data_device,
return -EINVAL; return -EINVAL;
} }
if (ARG_SET(OPT_SECTOR_SIZE_ID)) {
r = reencrypt_check_data_sb_block_size(data_device, ARG_UINT32(OPT_SECTOR_SIZE_ID));
if (r < 0)
return r;
}
if (!ARG_SET(OPT_UUID_ID)) { if (!ARG_SET(OPT_UUID_ID)) {
uuid_generate(uuid); uuid_generate(uuid);
uuid_unparse(uuid, uuid_str); uuid_unparse(uuid, uuid_str);
@@ -850,12 +890,28 @@ static int reencrypt_luks2_init(struct crypt_device *cd, const char *data_device
if (r < 0) if (r < 0)
goto out; goto out;
if (!ARG_SET(OPT_FORCE_OFFLINE_REENCRYPT_ID) && !ARG_SET(OPT_INIT_ONLY_ID)) /*
* with --init-only lookup active device only if
* blkid probes are allowed and sector size change
* is requested.
*/
if (!ARG_SET(OPT_FORCE_OFFLINE_REENCRYPT_ID) &&
(!ARG_SET(OPT_INIT_ONLY_ID) || (tools_blkid_supported() && sector_size_change))) {
r = reencrypt_get_active_name(cd, data_device, &active_name); r = reencrypt_get_active_name(cd, data_device, &active_name);
if (r >= 0) if (r < 0)
r = crypt_reencrypt_init_by_passphrase(cd, active_name, kp[keyslot_old].password, goto out;
kp[keyslot_old].passwordLen, keyslot_old, kp[keyslot_old].new, }
cipher, mode, &params);
if (sector_size_change && active_name) {
r = reencrypt_check_active_device_sb_block_size(active_name, luks2_params.sector_size);
if (r < 0)
goto out;
}
r = crypt_reencrypt_init_by_passphrase(cd,
ARG_SET(OPT_INIT_ONLY_ID) ? NULL : active_name,
kp[keyslot_old].password, kp[keyslot_old].passwordLen,
keyslot_old, kp[keyslot_old].new, cipher, mode, &params);
out: out:
crypt_safe_free(vk); crypt_safe_free(vk);
if (kp) { if (kp) {

View File

@@ -50,6 +50,7 @@ EXTRA_DIST = compatimage.img.xz compatv10image.img.xz \
conversion_imgs.tar.xz \ conversion_imgs.tar.xz \
luks2_keyslot_unassigned.img.xz \ luks2_keyslot_unassigned.img.xz \
img_fs_ext4.img.xz img_fs_vfat.img.xz img_fs_xfs.img.xz \ img_fs_ext4.img.xz img_fs_vfat.img.xz img_fs_xfs.img.xz \
xfs_512_block_size.img.xz \
valid_header_file.xz \ valid_header_file.xz \
luks2_valid_hdr.img.xz \ luks2_valid_hdr.img.xz \
luks2_header_requirements.xz \ luks2_header_requirements.xz \

View File

@@ -19,6 +19,7 @@ DEV_NAME2=reenc97682
IMG=reenc-data IMG=reenc-data
IMG_HDR=$IMG.hdr IMG_HDR=$IMG.hdr
HEADER_LUKS2_PV=blkid-luks2-pv.img HEADER_LUKS2_PV=blkid-luks2-pv.img
IMG_FS=xfs_512_block_size.img
KEY1=key1 KEY1=key1
VKEY1=vkey1 VKEY1=vkey1
PWD1="93R4P4pIqAH8" PWD1="93R4P4pIqAH8"
@@ -99,7 +100,7 @@ function remove_mapping()
[ -b /dev/mapper/$OVRDEV-err ] && dmsetup remove --retry $OVRDEV-err 2>/dev/null [ -b /dev/mapper/$OVRDEV-err ] && dmsetup remove --retry $OVRDEV-err 2>/dev/null
[ -n "$LOOPDEV" ] && losetup -d $LOOPDEV [ -n "$LOOPDEV" ] && losetup -d $LOOPDEV
unset LOOPDEV unset LOOPDEV
rm -f $IMG $IMG_HDR $KEY1 $VKEY1 $DEVBIG $DEV_LINK $HEADER_LUKS2_PV >/dev/null 2>&1 rm -f $IMG $IMG_HDR $KEY1 $VKEY1 $DEVBIG $DEV_LINK $HEADER_LUKS2_PV $IMG_FS >/dev/null 2>&1
rmmod scsi_debug >/dev/null 2>&1 rmmod scsi_debug >/dev/null 2>&1
scsi_debug_teardown $DEV scsi_debug_teardown $DEV
} }
@@ -717,6 +718,11 @@ function valgrind_run()
INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}" ./valg.sh ${CRYPTSETUP_VALGRIND} "$@" INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}" ./valg.sh ${CRYPTSETUP_VALGRIND} "$@"
} }
function bin_check()
{
command -v $1 >/dev/null || skip "WARNING: test require $1 binary, test skipped."
}
[ $(id -u) != 0 ] && skip "WARNING: You must be root to run this test, test skipped." [ $(id -u) != 0 ] && skip "WARNING: You must be root to run this test, test skipped."
[ ! -x "$CRYPTSETUP" ] && skip "Cannot find $CRYPTSETUP, test skipped." [ ! -x "$CRYPTSETUP" ] && skip "Cannot find $CRYPTSETUP, test skipped."
fips_mode && skip "This test cannot be run in FIPS mode." fips_mode && skip "This test cannot be run in FIPS mode."
@@ -1724,5 +1730,37 @@ $CRYPTSETUP isLuks $HEADER_LUKS2_PV && fail
echo $PWD1 | $CRYPTSETUP reencrypt -q --header $IMG_HDR $HEADER_LUKS2_PV $FAST_PBKDF_ARGON --encrypt --force-offline-reencrypt --type luks2 2>/dev/null && fail echo $PWD1 | $CRYPTSETUP reencrypt -q --header $IMG_HDR $HEADER_LUKS2_PV $FAST_PBKDF_ARGON --encrypt --force-offline-reencrypt --type luks2 2>/dev/null && fail
test -f $IMG_HDR && fail test -f $IMG_HDR && fail
echo "[31] Prevent dangerous sector size increase"
bin_check blkid
preparebig 64
xz -dk $IMG_FS.xz
blkid $IMG_FS | grep -q BLOCK_SIZE && BLKID_BLOCK_SIZE_SUPPORT=1
if [ -n "$DM_SECTOR_SIZE" -a -n "$BLKID_BLOCK_SIZE_SUPPORT" ]; then
# encryption checks must work in offline mode
echo $PWD1 | $CRYPTSETUP reencrypt --encrypt --force-offline-reencrypt --sector-size 1024 -q --header $IMG_HDR $IMG_FS $FAST_PBKDF_ARGON --init-only --type luks2 2>/dev/null && fail
test -f $IMG_HDR && fail
echo $PWD1 | $CRYPTSETUP reencrypt --encrypt --force-offline-reencrypt --sector-size 1024 -q --header $IMG_HDR $IMG_FS $FAST_PBKDF_ARGON --type luks2 2>/dev/null && fail
test -f $IMG_HDR && fail
echo $PWD1 | $CRYPTSETUP reencrypt --encrypt --force-offline-reencrypt --sector-size 1024 -q --reduce-device-size 8m $IMG_FS $FAST_PBKDF_ARGON --init-only --type luks2 2>/dev/null && fail
$CRYPTSETUP isLuks $IMG_FS && fail
echo $PWD1 | $CRYPTSETUP reencrypt --encrypt --force-offline-reencrypt --sector-size 1024 -q --reduce-device-size 8m $IMG_FS $FAST_PBKDF_ARGON --type luks2 2>/dev/null && fail
$CRYPTSETUP isLuks $IMG_FS && fail
echo $PWD1 | $CRYPTSETUP luksFormat -q --sector-size 512 --type luks2 $FAST_PBKDF_ARGON $DEV || fail
echo $PWD1 | $CRYPTSETUP open -q $DEV $DEV_NAME || fail
dd if=$IMG_FS of=/dev/mapper/$DEV_NAME bs=1M >/dev/null 2>&1
echo $PWD1 | $CRYPTSETUP reencrypt --init-only -q --sector-size 1024 $FAST_PBKDF_ARGON $DEV 2>/dev/null && fail
$CRYPTSETUP status $DEV_NAME | grep -q "reencryption: in-progress" && fail
echo $PWD1 | $CRYPTSETUP reencrypt --init-only -q --sector-size 1024 --active-name $DEV_NAME $FAST_PBKDF_ARGON 2>/dev/null && fail
$CRYPTSETUP status $DEV_NAME | grep -q "reencryption: in-progress" && fail
echo $PWD1 | $CRYPTSETUP reencrypt -q --sector-size 1024 $FAST_PBKDF_ARGON $DEV 2>/dev/null && fail
$CRYPTSETUP luksDump $DEV | grep -q "sector: 512" || fail
echo $PWD1 | $CRYPTSETUP reencrypt -q --sector-size 1024 --active-name $DEV_NAME $FAST_PBKDF_ARGON 2>/dev/null && fail
$CRYPTSETUP luksDump $DEV | grep -q "sector: 512" || fail
fi
remove_mapping remove_mapping
exit 0 exit 0

Binary file not shown.