Detect broken LUKS metadata in-before encryption.

We should abort LUKS device in-place encryption
when target data device or metadata device
contain broken LUKS metadata (any version).
Filed crypt_load() call was not good enough check
because the call fails also when a device contains
LUKS metadata overlapping with other superblock
(e.g. LVM2 PV signature).

Let blkid decide if device contains broken LUKS
metadata or not.

Fixes: #723.
This commit is contained in:
Ondrej Kozina
2022-04-07 16:26:56 +02:00
committed by Milan Broz
parent 412de7dc25
commit d56ccc97b8
5 changed files with 87 additions and 14 deletions

View File

@@ -112,7 +112,8 @@ int tools_write_json_file(const char *file, const char *json);
typedef enum {
PRB_FILTER_NONE = 0,
PRB_FILTER_LUKS
PRB_FILTER_LUKS,
PRB_ONLY_LUKS
} tools_probe_filter_info;
int tools_detect_signatures(const char *device, tools_probe_filter_info filter, size_t *count, bool batch_mode);

View File

@@ -220,12 +220,23 @@ int tools_detect_signatures(const char *device, tools_probe_filter_info filter,
return -EINVAL;
}
blk_set_chains_for_full_print(h);
if (filter == PRB_FILTER_LUKS && blk_superblocks_filter_luks(h)) {
switch (filter) {
case PRB_FILTER_LUKS:
if (blk_superblocks_filter_luks(h)) {
r = -EINVAL;
goto out;
}
/* fall-through */
case PRB_FILTER_NONE:
blk_set_chains_for_full_print(h);
break;
case PRB_ONLY_LUKS:
blk_set_chains_for_fast_detection(h);
if (blk_superblocks_only_luks(h)) {
r = -EINVAL;
goto out;
}
}
while ((pr = blk_probe(h)) < PRB_EMPTY) {
if (blk_is_partition(h))

View File

@@ -252,7 +252,6 @@ static enum device_status_info load_luks(struct crypt_device **r_cd, const char
if (crypt_init_data_device(&cd, uuid_or_device(header_device ?: data_device), data_device))
return DEVICE_INVALID;
/* TODO: LUKS2 load may fail when header is damaged and blkid reports ambiguous/other signatures */
if ((r = crypt_load(cd, CRYPT_LUKS, NULL))) {
crypt_free(cd);
@@ -924,10 +923,27 @@ static int reencrypt_luks2_resume(struct crypt_device *cd)
return r;
}
static int check_broken_luks_signature(const char *device)
{
int r;
size_t count;
r = tools_detect_signatures(device, PRB_ONLY_LUKS, &count, ARG_SET(OPT_BATCH_MODE_ID));
if (r < 0)
return -EINVAL;
if (count) {
log_err(_("Device %s contains broken LUKS metadata. Aborting operation."), device);
return -EINVAL;
}
return 0;
}
static int _encrypt(struct crypt_device *cd, const char *type, enum device_status_info dev_st, int action_argc, const char **action_argv)
{
const char *data_device;
const char *device_ptr;
enum device_status_info data_dev_st;
struct stat st;
struct crypt_device *encrypt_cd = NULL;
int r = -EINVAL;
@@ -937,24 +953,37 @@ static int _encrypt(struct crypt_device *cd, const char *type, enum device_statu
return -EINVAL;
}
if (dev_st == DEVICE_NOT_LUKS &&
(!ARG_SET(OPT_HEADER_ID) || !stat(ARG_STR(OPT_HEADER_ID), &st))) {
device_ptr = ARG_SET(OPT_HEADER_ID) ? ARG_STR(OPT_HEADER_ID) : action_argv[0];
r = check_broken_luks_signature(device_ptr);
if (r < 0)
return r;
}
/* check data device type/state */
if (ARG_SET(OPT_HEADER_ID)) {
data_device = cd ? crypt_get_device_name(cd) : action_argv[0];
data_dev_st = check_luks_device(data_device);
device_ptr = cd ? crypt_get_device_name(cd) : action_argv[0];
data_dev_st = check_luks_device(device_ptr);
if (data_dev_st == DEVICE_INVALID)
return -EINVAL;
if (data_dev_st == DEVICE_LUKS2 || data_dev_st == DEVICE_LUKS1) {
log_err(_("Device %s is already LUKS device. Aborting operation."),
data_device);
device_ptr);
return -EINVAL;
}
if (data_dev_st == DEVICE_LUKS2_REENCRYPT || data_dev_st == DEVICE_LUKS1_UNUSABLE) {
log_err(_("Device %s is already in LUKS reencryption. Aborting operation."),
data_device);
device_ptr);
return -EINVAL;
}
r = check_broken_luks_signature(device_ptr);
if (r < 0)
return r;
}
if (!type)

View File

@@ -18,6 +18,7 @@ DEV_NAME=reenc9768
DEV_NAME2=reenc97682
IMG=reenc-data
IMG_HDR=$IMG.hdr
HEADER_LUKS2_PV=blkid-luks2-pv.img
KEY1=key1
VKEY1=vkey1
PWD1="93R4P4pIqAH8"
@@ -98,7 +99,7 @@ function remove_mapping()
[ -b /dev/mapper/$OVRDEV-err ] && dmsetup remove --retry $OVRDEV-err 2>/dev/null
[ -n "$LOOPDEV" ] && losetup -d $LOOPDEV
unset LOOPDEV
rm -f $IMG $IMG_HDR $KEY1 $VKEY1 $DEVBIG $DEV_LINK >/dev/null 2>&1
rm -f $IMG $IMG_HDR $KEY1 $VKEY1 $DEVBIG $DEV_LINK $HEADER_LUKS2_PV >/dev/null 2>&1
rmmod scsi_debug >/dev/null 2>&1
scsi_debug_teardown $DEV
}
@@ -1708,5 +1709,20 @@ echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 --header $IMG_HDR $FAST_PBKD
echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q --decrypt --header $IMG_HDR --init-only $FAST_PBKDF_ARGON || fail
echo $PWD1 | $CRYPTSETUP reencrypt --encrypt --header $IMG_HDR $DEV -q $FAST_PBKDF_ARGON 2> /dev/null && fail
echo "[30] Prevent nested encryption of broken LUKS device"
rm -f $IMG_HDR
xz -dk $HEADER_LUKS2_PV.xz
wipe_dev $DEV
# broken header
echo $PWD1 | $CRYPTSETUP reencrypt -q --header $HEADER_LUKS2_PV $DEV $FAST_PBKDF --encrypt --type luks2 2>/dev/null && fail
$CRYPTSETUP isLuks $HEADER_LUKS2_PV && fail
# broken device
echo $PWD1 | $CRYPTSETUP reencrypt -q $HEADER_LUKS2_PV $FAST_PBKDF --encrypt --force-offline-reencrypt --type luks2 --reduce-device-size 8m 2>/dev/null && fail
$CRYPTSETUP isLuks $HEADER_LUKS2_PV && fail
# broken data device only
echo $PWD1 | $CRYPTSETUP reencrypt -q --header $IMG_HDR $HEADER_LUKS2_PV $FAST_PBKDF --encrypt --force-offline-reencrypt --type luks2 2>/dev/null && fail
test -f $IMG_HDR && fail
remove_mapping
exit 0

View File

@@ -10,6 +10,7 @@ DEV_NAME=reenc9768
DEV_NAME2=reenc1273
IMG=reenc-data
IMG_HDR=$IMG.hdr
HEADER_LUKS2_PV=blkid-luks2-pv.img
ORIG_IMG=reenc-data-orig
KEY1=key1
PWD1="93R4P4pIqAH8"
@@ -30,7 +31,7 @@ function remove_mapping()
[ -b /dev/mapper/$DEV_NAME2 ] && dmsetup remove --retry $DEV_NAME2
[ -b /dev/mapper/$DEV_NAME ] && dmsetup remove --retry $DEV_NAME
[ ! -z "$LOOPDEV1" ] && losetup -d $LOOPDEV1 >/dev/null 2>&1
rm -f $IMG $IMG_HDR $ORIG_IMG $KEY1 >/dev/null 2>&1
rm -f $IMG $IMG_HDR $ORIG_IMG $KEY1 $HEADER_LUKS2_PV >/dev/null 2>&1
umount $MNT_DIR > /dev/null 2>&1
rmdir $MNT_DIR > /dev/null 2>&1
LOOPDEV1=""
@@ -416,5 +417,20 @@ echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks1 --header $IMG_HDR $FAST_PBKD
echo $PWD1 | $REENC $LOOPDEV1 -q $FAST_PBKDF --new --type luks1 --header $IMG_HDR 2>/dev/null && fail
echo $PWD1 | $REENC $LOOPDEV1 -q $FAST_PBKDF --new --type luks2 --header $IMG_HDR 2>/dev/null && fail
echo "[13] Prevent nested encryption of broken LUKS device"
rm -f $IMG_HDR
wipe_dev $LOOPDEV1
xz -dk $HEADER_LUKS2_PV.xz
# broken header
echo $PWD1 | $REENC --header $HEADER_LUKS2_PV $LOOPDEV1 -q $FAST_PBKDF --new --type luks1 2>/dev/null && fail
$CRYPTSETUP isLuks $HEADER_LUKS2_PV && fail
# broken device
echo $PWD1 | $REENC $HEADER_LUKS2_PV -q $FAST_PBKDF --new --type luks1 --reduce-device-size 1024S 2>/dev/null && fail
$CRYPTSETUP isLuks $HEADER_LUKS2_PV && fail
# broken data device only
echo $PWD1 | $REENC --header $IMG_HDR $HEADER_LUKS2_PV -q $FAST_PBKDF --new --type luks1 2>/dev/null && fail
test -f $IMG_HDR && fail
remove_mapping
exit 0